/* Copyright (c) 2003-2008 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define DBTC_C #include "Dbtc.hpp" #include "md5_hash.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Use DEBUG to print messages that should be // seen only when we debug the product #ifdef VM_TRACE #define DEBUG(x) ndbout << "DBTC: "<< x << endl; #else #define DEBUG(x) #endif #define INTERNAL_TRIGGER_TCKEYREQ_JBA 0 #ifdef VM_TRACE NdbOut & operator<<(NdbOut& out, Dbtc::ConnectionState state){ switch(state){ case Dbtc::CS_CONNECTED: out << "CS_CONNECTED"; break; case Dbtc::CS_DISCONNECTED: out << "CS_DISCONNECTED"; break; case Dbtc::CS_STARTED: out << "CS_STARTED"; break; case Dbtc::CS_RECEIVING: out << "CS_RECEIVING"; break; case Dbtc::CS_PREPARED: out << "CS_PREPARED"; break; case Dbtc::CS_START_PREPARING: out << "CS_START_PREPARING"; break; case Dbtc::CS_REC_PREPARING: out << "CS_REC_PREPARING"; break; case Dbtc::CS_RESTART: out << "CS_RESTART"; break; case Dbtc::CS_ABORTING: out << "CS_ABORTING"; break; case Dbtc::CS_COMPLETING: out << "CS_COMPLETING"; break; case Dbtc::CS_COMPLETE_SENT: out << "CS_COMPLETE_SENT"; break; case Dbtc::CS_PREPARE_TO_COMMIT: out << "CS_PREPARE_TO_COMMIT"; break; case Dbtc::CS_COMMIT_SENT: out << "CS_COMMIT_SENT"; break; case Dbtc::CS_START_COMMITTING: out << "CS_START_COMMITTING"; break; case Dbtc::CS_COMMITTING: out << "CS_COMMITTING"; break; case Dbtc::CS_REC_COMMITTING: out << "CS_REC_COMMITTING"; break; case Dbtc::CS_WAIT_ABORT_CONF: out << "CS_WAIT_ABORT_CONF"; break; case Dbtc::CS_WAIT_COMPLETE_CONF: out << "CS_WAIT_COMPLETE_CONF"; break; case Dbtc::CS_WAIT_COMMIT_CONF: out << "CS_WAIT_COMMIT_CONF"; break; case Dbtc::CS_FAIL_ABORTING: out << "CS_FAIL_ABORTING"; break; case Dbtc::CS_FAIL_ABORTED: out << "CS_FAIL_ABORTED"; break; case Dbtc::CS_FAIL_PREPARED: out << "CS_FAIL_PREPARED"; break; case Dbtc::CS_FAIL_COMMITTING: out << "CS_FAIL_COMMITTING"; break; case Dbtc::CS_FAIL_COMMITTED: out << "CS_FAIL_COMMITTED"; break; case Dbtc::CS_FAIL_COMPLETED: out << "CS_FAIL_COMPLETED"; break; case Dbtc::CS_START_SCAN: out << "CS_START_SCAN"; break; default: out << "Unknown: " << (int)state; break; } return out; } NdbOut & operator<<(NdbOut& out, Dbtc::OperationState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dbtc::AbortState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dbtc::ReturnSignal state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dbtc::ScanRecord::ScanState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dbtc::ScanFragRec::ScanFragState state){ out << (int)state; return out; } #endif void Dbtc::updateBuddyTimer(ApiConnectRecordPtr apiPtr) { if (apiPtr.p->buddyPtr != RNIL) { jam(); ApiConnectRecordPtr buddyApiPtr; buddyApiPtr.i = apiPtr.p->buddyPtr; ptrCheckGuard(buddyApiPtr, capiConnectFilesize, apiConnectRecord); if (getApiConTimer(buddyApiPtr.i) != 0) { if ((apiPtr.p->transid[0] == buddyApiPtr.p->transid[0]) && (apiPtr.p->transid[1] == buddyApiPtr.p->transid[1])) { jam(); setApiConTimer(buddyApiPtr.i, ctcTimer, __LINE__); } else { jam(); // Not a buddy anymore since not the same transid apiPtr.p->buddyPtr = RNIL; }//if }//if }//if } void Dbtc::execCONTINUEB(Signal* signal) { UintR tcase; jamEntry(); tcase = signal->theData[0]; UintR Tdata0 = signal->theData[1]; UintR Tdata1 = signal->theData[2]; UintR Tdata2 = signal->theData[3]; switch (tcase) { case TcContinueB::ZRETURN_FROM_QUEUED_DELIVERY: jam(); ndbrequire(false); return; case TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER: jam(); tcNodeFailptr.i = Tdata0; ptrCheckGuard(tcNodeFailptr, 1, tcFailRecord); completeTransAtTakeOverLab(signal, Tdata1); return; case TcContinueB::ZCONTINUE_TIME_OUT_CONTROL: jam(); timeOutLoopStartLab(signal, Tdata0); return; case TcContinueB::ZNODE_TAKE_OVER_COMPLETED: jam(); tnodeid = Tdata0; tcNodeFailptr.i = 0; ptrAss(tcNodeFailptr, tcFailRecord); nodeTakeOverCompletedLab(signal); return; case TcContinueB::ZINITIALISE_RECORDS: jam(); initialiseRecordsLab(signal, Tdata0, Tdata2, signal->theData[4]); return; case TcContinueB::ZSEND_COMMIT_LOOP: jam(); apiConnectptr.i = Tdata0; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); tcConnectptr.i = Tdata1; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); commit020Lab(signal); return; case TcContinueB::ZSEND_COMPLETE_LOOP: jam(); apiConnectptr.i = Tdata0; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); tcConnectptr.i = Tdata1; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); complete010Lab(signal); return; case TcContinueB::ZHANDLE_FAILED_API_NODE: jam(); handleFailedApiNode(signal, Tdata0, Tdata1); return; case TcContinueB::ZTRANS_EVENT_REP: jam(); /* -------------------------------------------------------------------- */ // Report information about transaction activity once per second. /* -------------------------------------------------------------------- */ if (c_counters.c_trans_status == TransCounters::Timer){ Uint32 len = c_counters.report(signal); sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, len, JBB); c_counters.reset(); signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 1); } return; case TcContinueB::ZCONTINUE_TIME_OUT_FRAG_CONTROL: jam(); timeOutLoopStartFragLab(signal, Tdata0); return; case TcContinueB::ZABORT_BREAK: jam(); tcConnectptr.i = Tdata0; apiConnectptr.i = Tdata1; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->counter--; abort015Lab(signal); return; case TcContinueB::ZABORT_TIMEOUT_BREAK: jam(); tcConnectptr.i = Tdata0; apiConnectptr.i = Tdata1; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->counter--; sendAbortedAfterTimeout(signal, 1); return; case TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS: jam(); removeMarkerForFailedAPI(signal, Tdata0, Tdata1); return; case TcContinueB::ZWAIT_ABORT_ALL: jam(); checkAbortAllTimeout(signal, Tdata0); return; case TcContinueB::ZCHECK_SCAN_ACTIVE_FAILED_LQH: jam(); checkScanActiveInFailedLqh(signal, Tdata0, Tdata1); return; case TcContinueB::ZNF_CHECK_TRANSACTIONS: jam(); nodeFailCheckTransactions(signal, Tdata0, Tdata1); return; case TcContinueB::CHECK_WAIT_DROP_TAB_FAILED_LQH: jam(); checkWaitDropTabFailedLqh(signal, Tdata0, Tdata1); return; case TcContinueB::TRIGGER_PENDING: jam(); ApiConnectRecordPtr transPtr; transPtr.i = Tdata0; ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord); transPtr.p->triggerPending = false; executeTriggers(signal, &transPtr); return; case TcContinueB::DelayTCKEYCONF: jam(); apiConnectptr.i = Tdata0; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); sendtckeyconf(signal, Tdata1); return; default: ndbrequire(false); }//switch } void Dbtc::execDIGETNODESREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; releaseAtErrorLab(signal); } void Dbtc::execINCL_NODEREQ(Signal* signal) { jamEntry(); tblockref = signal->theData[0]; hostptr.i = signal->theData[1]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); hostptr.p->hostStatus = HS_ALIVE; c_alive_nodes.set(hostptr.i); signal->theData[0] = hostptr.i; signal->theData[1] = cownref; if (ERROR_INSERTED(8039)) { CLEAR_ERROR_INSERT_VALUE; Uint32 save = signal->theData[0]; signal->theData[0] = 9999; sendSignal(numberToRef(CMVMI, hostptr.i), GSN_NDB_TAMPER, signal, 1, JBB); signal->theData[0] = save; sendSignalWithDelay(tblockref, GSN_INCL_NODECONF, signal, 5000, 2); return; } sendSignal(tblockref, GSN_INCL_NODECONF, signal, 2, JBB); } void Dbtc::execREAD_NODESREF(Signal* signal) { jamEntry(); ndbrequire(false); } void Dbtc::execTC_SCHVERREQ(Signal* signal) { jamEntry(); if (! assembleFragments(signal)) { jam(); return; } tabptr.i = signal->theData[0]; ptrCheckGuard(tabptr, ctabrecFilesize, tableRecord); tabptr.p->currentSchemaVersion = signal->theData[1]; tabptr.p->m_flags = 0; tabptr.p->set_storedTable((bool)signal->theData[2]); BlockReference retRef = signal->theData[3]; tabptr.p->tableType = (Uint8)signal->theData[4]; BlockReference retPtr = signal->theData[5]; Uint32 noOfKeyAttr = signal->theData[6]; tabptr.p->singleUserMode = (Uint8)signal->theData[7]; ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX); const KeyDescriptor* desc = g_key_descriptor_pool.getPtr(tabptr.i); ndbrequire(noOfKeyAttr == desc->noOfKeyAttr); ndbrequire(tabptr.p->get_enabled() == false); tabptr.p->set_enabled(true); tabptr.p->set_dropping(false); tabptr.p->noOfKeyAttr = desc->noOfKeyAttr; tabptr.p->hasCharAttr = desc->hasCharAttr; tabptr.p->noOfDistrKeys = desc->noOfDistrKeys; tabptr.p->hasVarKeys = desc->noOfVarKeys > 0; signal->theData[0] = tabptr.i; signal->theData[1] = retPtr; sendSignal(retRef, GSN_TC_SCHVERCONF, signal, 2, JBB); }//Dbtc::execTC_SCHVERREQ() void Dbtc::execPREP_DROP_TAB_REQ(Signal* signal) { jamEntry(); PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); TableRecordPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); Uint32 senderRef = req->senderRef; Uint32 senderData = req->senderData; if(!tabPtr.p->get_enabled()){ jam(); PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = PrepDropTabRef::NoSuchTable; sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal, PrepDropTabRef::SignalLength, JBB); return; } if(tabPtr.p->get_dropping()){ jam(); PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = PrepDropTabRef::DropInProgress; sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal, PrepDropTabRef::SignalLength, JBB); return; } tabPtr.p->set_dropping(true); tabPtr.p->dropTable.senderRef = senderRef; tabPtr.p->dropTable.senderData = senderData; { WaitDropTabReq * req = (WaitDropTabReq*)signal->getDataPtrSend(); req->tableId = tabPtr.i; req->senderRef = reference(); HostRecordPtr hostPtr; tabPtr.p->dropTable.waitDropTabCount.clearWaitingFor(); for (hostPtr.i = 1; hostPtr.i < MAX_NDB_NODES; hostPtr.i++) { jam(); ptrAss(hostPtr, hostRecord); if (hostPtr.p->hostStatus == HS_ALIVE) { jam(); tabPtr.p->dropTable.waitDropTabCount.setWaitingFor(hostPtr.i); sendSignal(calcLqhBlockRef(hostPtr.i), GSN_WAIT_DROP_TAB_REQ, signal, WaitDropTabReq::SignalLength, JBB); }//for }//if ndbrequire(tabPtr.p->dropTable.waitDropTabCount.done() != true); } } void Dbtc::execWAIT_DROP_TAB_CONF(Signal* signal) { jamEntry(); WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtr(); TableRecordPtr tabPtr; tabPtr.i = conf->tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); ndbrequire(tabPtr.p->get_dropping() == true); Uint32 nodeId = refToNode(conf->senderRef); tabPtr.p->dropTable.waitDropTabCount.clearWaitingFor(nodeId); if(!tabPtr.p->dropTable.waitDropTabCount.done()){ jam(); return; } { PrepDropTabConf* conf = (PrepDropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); conf->senderData = tabPtr.p->dropTable.senderData; sendSignal(tabPtr.p->dropTable.senderRef, GSN_PREP_DROP_TAB_CONF, signal, PrepDropTabConf::SignalLength, JBB); tabPtr.p->dropTable.senderRef = 0; } } void Dbtc::execWAIT_DROP_TAB_REF(Signal* signal) { jamEntry(); WaitDropTabRef * ref = (WaitDropTabRef*)signal->getDataPtr(); TableRecordPtr tabPtr; tabPtr.i = ref->tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); ndbrequire(tabPtr.p->get_dropping() == true); Uint32 nodeId = refToNode(ref->senderRef); tabPtr.p->dropTable.waitDropTabCount.clearWaitingFor(nodeId); ndbrequire(ref->errorCode == WaitDropTabRef::NoSuchTable || ref->errorCode == WaitDropTabRef::NF_FakeErrorREF); if(!tabPtr.p->dropTable.waitDropTabCount.done()){ jam(); return; } { PrepDropTabConf* conf = (PrepDropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); conf->senderData = tabPtr.p->dropTable.senderData; sendSignal(tabPtr.p->dropTable.senderRef, GSN_PREP_DROP_TAB_CONF, signal, PrepDropTabConf::SignalLength, JBB); tabPtr.p->dropTable.senderRef = 0; } } void Dbtc::checkWaitDropTabFailedLqh(Signal* signal, Uint32 nodeId, Uint32 tableId) { TableRecordPtr tabPtr; tabPtr.i = tableId; WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtr(); conf->tableId = tableId; const Uint32 RT_BREAK = 16; for(Uint32 i = 0; iget_enabled() && tabPtr.p->get_dropping()){ if(tabPtr.p->dropTable.waitDropTabCount.isWaitingFor(nodeId)){ jam(); conf->senderRef = calcLqhBlockRef(nodeId); execWAIT_DROP_TAB_CONF(signal); tabPtr.i++; break; } } } if(tabPtr.i == ctabrecFilesize){ /** * Finished */ jam(); checkNodeFailComplete(signal, nodeId, HostRecord::NF_CHECK_DROP_TAB); return; } signal->theData[0] = TcContinueB::CHECK_WAIT_DROP_TAB_FAILED_LQH; signal->theData[1] = nodeId; signal->theData[2] = tabPtr.i; sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB); } void Dbtc::execDROP_TAB_REQ(Signal* signal) { jamEntry(); DropTabReq* req = (DropTabReq*)signal->getDataPtr(); TableRecordPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); Uint32 senderRef = req->senderRef; Uint32 senderData = req->senderData; DropTabReq::RequestType rt = (DropTabReq::RequestType)req->requestType; if(!tabPtr.p->get_enabled() && rt == DropTabReq::OnlineDropTab){ jam(); DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = DropTabRef::NoSuchTable; sendSignal(senderRef, GSN_DROP_TAB_REF, signal, DropTabRef::SignalLength, JBB); return; } if(!tabPtr.p->get_dropping() && rt == DropTabReq::OnlineDropTab){ jam(); DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = DropTabRef::DropWoPrep; sendSignal(senderRef, GSN_DROP_TAB_REF, signal, DropTabRef::SignalLength, JBB); return; } tabPtr.p->set_enabled(false); tabPtr.p->set_dropping(false); DropTabConf * conf = (DropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); conf->senderData = senderData; sendSignal(senderRef, GSN_DROP_TAB_CONF, signal, PrepDropTabConf::SignalLength, JBB); } void Dbtc::execALTER_TAB_REQ(Signal * signal) { AlterTabReq* const req = (AlterTabReq*)signal->getDataPtr(); const Uint32 senderRef = req->senderRef; const Uint32 senderData = req->senderData; const Uint32 changeMask = req->changeMask; const Uint32 tableId = req->tableId; const Uint32 tableVersion = req->tableVersion; const Uint32 gci = req->gci; AlterTabReq::RequestType requestType = (AlterTabReq::RequestType) req->requestType; TableRecordPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); tabPtr.p->currentSchemaVersion = tableVersion; // Request handled successfully AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); conf->senderRef = reference(); conf->senderData = senderData; conf->changeMask = changeMask; conf->tableId = tableId; conf->tableVersion = tableVersion; conf->gci = gci; conf->requestType = requestType; sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal, AlterTabConf::SignalLength, JBB); } /* ***************************************************************************/ /* START / RESTART */ /* ***************************************************************************/ void Dbtc::execREAD_CONFIG_REQ(Signal* signal) { const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); Uint32 ref = req->senderRef; Uint32 senderData = req->senderData; ndbrequire(req->noOfParameters == 0); jamEntry(); const ndb_mgm_configuration_iterator * p = m_ctx.m_config.getOwnConfigIterator(); ndbrequire(p != 0); initData(); UintR apiConnect; UintR tcConnect; UintR tables; UintR localScan; UintR tcScan; ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_API_CONNECT, &apiConnect)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_TC_CONNECT, &tcConnect)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_TABLE, &tables)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_LOCAL_SCAN, &localScan)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TC_SCAN, &tcScan)); ccacheFilesize = (apiConnect/3) + 1; capiConnectFilesize = apiConnect; ctcConnectFilesize = tcConnect; ctabrecFilesize = tables; cscanrecFileSize = tcScan; cscanFragrecFileSize = localScan; initRecords(); initialiseRecordsLab(signal, 0, ref, senderData); Uint32 val = 3000; ndb_mgm_get_int_parameter(p, CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT, &val); set_timeout_value(val); val = 1500; ndb_mgm_get_int_parameter(p, CFG_DB_HEARTBEAT_INTERVAL, &val); cDbHbInterval = (val < 10) ? 10 : val; val = 3000; ndb_mgm_get_int_parameter(p, CFG_DB_TRANSACTION_INACTIVE_TIMEOUT, &val); set_appl_timeout_value(val); val = 1; //ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_TRANSACTION_TAKEOVER, &val); set_no_parallel_takeover(val); ctimeOutCheckDelay = 50; // 500ms }//Dbtc::execSIZEALT_REP() void Dbtc::execSTTOR(Signal* signal) { Uint16 tphase; jamEntry(); /* START CASE */ tphase = signal->theData[1]; csignalKey = signal->theData[6]; switch (tphase) { case ZSPH1: jam(); startphase1x010Lab(signal); return; default: jam(); sttorryLab(signal); /* START PHASE 255 */ return; }//switch }//Dbtc::execSTTOR() void Dbtc::sttorryLab(Signal* signal) { signal->theData[0] = csignalKey; signal->theData[1] = 3; /* BLOCK CATEGORY */ signal->theData[2] = 2; /* SIGNAL VERSION NUMBER */ signal->theData[3] = ZSPH1; signal->theData[4] = 255; sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 5, JBB); }//Dbtc::sttorryLab() /* ***************************************************************************/ /* INTERNAL START / RESTART */ /*****************************************************************************/ void Dbtc::execNDB_STTOR(Signal* signal) { Uint16 tndbstartphase; Uint16 tstarttype; jamEntry(); tusersblkref = signal->theData[0]; tnodeid = signal->theData[1]; tndbstartphase = signal->theData[2]; /* START PHASE */ tstarttype = signal->theData[3]; /* START TYPE */ switch (tndbstartphase) { case ZINTSPH1: jam(); intstartphase1x010Lab(signal); return; case ZINTSPH2: jam(); intstartphase2x010Lab(signal); return; case ZINTSPH3: jam(); intstartphase3x010Lab(signal); /* SEIZE CONNECT RECORD IN EACH LQH*/ // Start transaction event reporting. c_counters.c_trans_status = TransCounters::Timer; c_counters.reset(); signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 1); return; case ZINTSPH6: jam(); csystemStart = SSS_TRUE; break; default: jam(); break; }//switch ndbsttorry010Lab(signal); return; }//Dbtc::execNDB_STTOR() void Dbtc::ndbsttorry010Lab(Signal* signal) { signal->theData[0] = cownref; sendSignal(cndbcntrblockref, GSN_NDB_STTORRY, signal, 1, JBB); }//Dbtc::ndbsttorry010Lab() void Dbtc::set_timeout_value(Uint32 timeOut) { timeOut = timeOut / 10; if (timeOut < 2) { jam(); timeOut = 100; }//if ctimeOutValue = timeOut; } void Dbtc::set_appl_timeout_value(Uint32 timeOut) { if (timeOut) { timeOut /= 10; if (timeOut < ctimeOutValue) { jam(); c_appl_timeout_value = ctimeOutValue; }//if } c_appl_timeout_value = timeOut; } void Dbtc::set_no_parallel_takeover(Uint32 noParallelTakeOver) { if (noParallelTakeOver == 0) { jam(); noParallelTakeOver = 1; } else if (noParallelTakeOver > MAX_NDB_NODES) { jam(); noParallelTakeOver = MAX_NDB_NODES; }//if cnoParallelTakeOver = noParallelTakeOver; } /* ***************************************************************************/ /* S T A R T P H A S E 1 X */ /* INITIALISE BLOCKREF AND BLOCKNUMBERS */ /* ***************************************************************************/ void Dbtc::startphase1x010Lab(Signal* signal) { csystemStart = SSS_FALSE; ctimeOutCheckCounter = 0; ctimeOutCheckFragCounter = 0; ctimeOutMissedHeartbeats = 0; ctimeOutCheckHeartbeat = 0; ctimeOutCheckLastHeartbeat = 0; ctimeOutCheckActive = TOCS_FALSE; ctimeOutCheckFragActive = TOCS_FALSE; sttorryLab(signal); }//Dbtc::startphase1x010Lab() /*****************************************************************************/ /* I N T S T A R T P H A S E 1 X */ /* INITIALISE ALL RECORDS. */ /*****************************************************************************/ void Dbtc::intstartphase1x010Lab(Signal* signal) { cownNodeid = tnodeid; cownref = calcTcBlockRef(cownNodeid); clqhblockref = calcLqhBlockRef(cownNodeid); cdihblockref = calcDihBlockRef(cownNodeid); cdictblockref = calcDictBlockRef(cownNodeid); cndbcntrblockref = calcNdbCntrBlockRef(cownNodeid); cerrorBlockref = calcNdbCntrBlockRef(cownNodeid); coperationsize = 0; cfailure_nr = 0; ndbsttorry010Lab(signal); }//Dbtc::intstartphase1x010Lab() /*****************************************************************************/ /* I N T S T A R T P H A S E 2 X */ /* SET-UP LOCAL CONNECTIONS. */ /*****************************************************************************/ void Dbtc::intstartphase2x010Lab(Signal* signal) { tcConnectptr.i = cfirstfreeTcConnect; intstartphase2x020Lab(signal); }//Dbtc::intstartphase2x010Lab() void Dbtc::intstartphase2x020Lab(Signal* signal) { if (tcConnectptr.i == RNIL) { jam(); ndbsttorry010Lab(signal); return; }//if ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); tcConnectptr.p->tcConnectstate = OS_CONNECTING_DICT; /* ****************** */ /* DISEIZEREQ < */ /* ****************** */ signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; sendSignal(cdihblockref, GSN_DISEIZEREQ, signal, 2, JBB); }//Dbtc::intstartphase2x020Lab() void Dbtc::execDISEIZECONF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); tcConnectptr.p->dihConnectptr = signal->theData[1]; tcConnectptr.i = tcConnectptr.p->nextTcConnect; intstartphase2x020Lab(signal); }//Dbtc::execDISEIZECONF() /*****************************************************************************/ /* I N T S T A R T P H A S E 3 X */ /* PREPARE DISTRIBUTED CONNECTIONS */ /*****************************************************************************/ void Dbtc::intstartphase3x010Lab(Signal* signal) { signal->theData[0] = cownref; sendSignal(cndbcntrblockref, GSN_READ_NODESREQ, signal, 1, JBB); }//Dbtc::intstartphase3x010Lab() void Dbtc::execREAD_NODESCONF(Signal* signal) { UintR guard0; jamEntry(); ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0]; csystemnodes = readNodes->noOfNodes; cmasterNodeId = readNodes->masterNodeId; con_lineNodes = 0; arrGuard(csystemnodes, MAX_NDB_NODES); guard0 = csystemnodes - 1; arrGuard(guard0, MAX_NDB_NODES); // Check not zero nodes for (unsigned i = 1; i < MAX_NDB_NODES; i++) { jam(); if (NodeBitmask::get(readNodes->allNodes, i)) { hostptr.i = i; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (NodeBitmask::get(readNodes->inactiveNodes, i)) { jam(); hostptr.p->hostStatus = HS_DEAD; } else { jam(); con_lineNodes++; hostptr.p->hostStatus = HS_ALIVE; c_alive_nodes.set(i); }//if }//if }//for ndbsttorry010Lab(signal); }//Dbtc::execREAD_NODESCONF() /*****************************************************************************/ /* A P I _ F A I L R E Q */ // An API node has failed for some reason. We need to disconnect all API // connections to the API node. This also includes /*****************************************************************************/ void Dbtc::execAPI_FAILREQ(Signal* signal) { /*************************************************************************** * Set the block reference to return API_FAILCONF to. Set the number of api * connects currently closing to one to indicate that we are still in the * process of going through the api connect records. Thus checking for zero * can only be true after all api connect records have been checked. **************************************************************************/ jamEntry(); capiFailRef = signal->theData[1]; arrGuard(signal->theData[0], MAX_NODES); capiConnectClosing[signal->theData[0]] = 1; handleFailedApiNode(signal, signal->theData[0], (UintR)0); } void Dbtc::handleFailedApiNode(Signal* signal, UintR TapiFailedNode, UintR TapiConnectPtr) { UintR TloopCount = 0; arrGuard(TapiFailedNode, MAX_NODES); apiConnectptr.i = TapiConnectPtr; do { ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); const UintR TapiNode = refToNode(apiConnectptr.p->ndbapiBlockref); if (TapiNode == TapiFailedNode) { #ifdef VM_TRACE if (apiConnectptr.p->apiFailState != ZFALSE) { ndbout << "Error in previous API fail handling discovered" << endl << " apiConnectptr.i = " << apiConnectptr.i << endl << " apiConnectstate = " << apiConnectptr.p->apiConnectstate << endl << " ndbapiBlockref = " << hex << apiConnectptr.p->ndbapiBlockref << endl << " apiNode = " << refToNode(apiConnectptr.p->ndbapiBlockref) << endl; if (apiConnectptr.p->lastTcConnect != RNIL){ jam(); tcConnectptr.i = apiConnectptr.p->lastTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); ndbout << " tcConnectptr.i = " << tcConnectptr.i << endl << " tcConnectstate = " << tcConnectptr.p->tcConnectstate << endl; } }//if #endif apiConnectptr.p->returnsignal = RS_NO_RETURN; /***********************************************************************/ // The connected node is the failed node. /**********************************************************************/ switch(apiConnectptr.p->apiConnectstate) { case CS_DISCONNECTED: /*********************************************************************/ // These states do not need any special handling. // Simply continue with the next. /*********************************************************************/ jam(); break; case CS_ABORTING: /*********************************************************************/ // This could actually mean that the API connection is already // ready to release if the abortState is IDLE. /*********************************************************************/ if (apiConnectptr.p->abortState == AS_IDLE) { jam(); releaseApiCon(signal, apiConnectptr.i); } else { jam(); capiConnectClosing[TapiFailedNode]++; apiConnectptr.p->apiFailState = ZTRUE; }//if break; case CS_WAIT_ABORT_CONF: case CS_WAIT_COMMIT_CONF: case CS_START_COMMITTING: case CS_PREPARE_TO_COMMIT: case CS_COMMITTING: case CS_COMMIT_SENT: /*********************************************************************/ // These states indicate that an abort process or commit process is // already ongoing. We will set a state in the api record indicating // that the API node has failed. // Also we will increase the number of outstanding api records to // wait for before we can respond with API_FAILCONF. /*********************************************************************/ jam(); capiConnectClosing[TapiFailedNode]++; apiConnectptr.p->apiFailState = ZTRUE; break; case CS_START_SCAN: /*********************************************************************/ // The api record was performing a scan operation. We need to check // on the scan state. Since completing a scan process might involve // sending several signals we will increase the loop count by 64. /*********************************************************************/ jam(); apiConnectptr.p->apiFailState = ZTRUE; capiConnectClosing[TapiFailedNode]++; ScanRecordPtr scanPtr; scanPtr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanPtr, cscanrecFileSize, scanRecord); close_scan_req(signal, scanPtr, true); TloopCount += 64; break; case CS_CONNECTED: case CS_REC_COMMITTING: case CS_RECEIVING: case CS_STARTED: /*********************************************************************/ // The api record was in the process of performing a transaction but // had not yet sent all information. // We need to initiate an ABORT since the API will not provide any // more information. // Since the abort can send many signals we will insert a real-time // break after checking this record. /*********************************************************************/ jam(); apiConnectptr.p->apiFailState = ZTRUE; capiConnectClosing[TapiFailedNode]++; abort010Lab(signal); TloopCount = 256; break; case CS_PREPARED: jam(); case CS_REC_PREPARING: jam(); case CS_START_PREPARING: jam(); /*********************************************************************/ // Not implemented yet. /*********************************************************************/ systemErrorLab(signal, __LINE__); break; case CS_RESTART: jam(); case CS_COMPLETING: jam(); case CS_COMPLETE_SENT: jam(); case CS_WAIT_COMPLETE_CONF: jam(); case CS_FAIL_ABORTING: jam(); case CS_FAIL_ABORTED: jam(); case CS_FAIL_PREPARED: jam(); case CS_FAIL_COMMITTING: jam(); case CS_FAIL_COMMITTED: /*********************************************************************/ // These states are only valid on copy and fail API connections. /*********************************************************************/ default: jam(); systemErrorLab(signal, __LINE__); break; }//switch } else { jam(); }//if apiConnectptr.i++; if (apiConnectptr.i > ((capiConnectFilesize / 3) - 1)) { jam(); /** * Finished with scanning connection record * * Now scan markers */ removeMarkerForFailedAPI(signal, TapiFailedNode, 0); return; }//if } while (TloopCount++ < 256); signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE; signal->theData[1] = TapiFailedNode; signal->theData[2] = apiConnectptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); }//Dbtc::handleFailedApiNode() void Dbtc::removeMarkerForFailedAPI(Signal* signal, Uint32 nodeId, Uint32 startBucket) { TcFailRecordPtr node_fail_ptr; node_fail_ptr.i = 0; ptrAss(node_fail_ptr, tcFailRecord); if(node_fail_ptr.p->failStatus != FS_IDLE) { jam(); DEBUG("Restarting removeMarkerForFailedAPI"); /** * TC take-over in progress * needs to restart as this * creates new markers */ signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS; signal->theData[1] = nodeId; signal->theData[2] = 0; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 500, 3); return; } CommitAckMarkerIterator iter; m_commitAckMarkerHash.next(startBucket, iter); const Uint32 RT_BREAK = 256; for(Uint32 i = 0; itheData[0] = nodeId; signal->theData[1] = cownref; sendSignal(capiFailRef, GSN_API_FAILCONF, signal, 2, JBB); } return; } if(iter.curr.p->apiNodeId == nodeId){ jam(); /** * Check so that the record is not still in use * */ ApiConnectRecordPtr apiConnectPtr; apiConnectPtr.i = iter.curr.p->apiConnectPtr; ptrCheckGuard(apiConnectPtr, capiConnectFilesize, apiConnectRecord); if(apiConnectPtr.p->commitAckMarker == iter.curr.i){ jam(); /** * The record is still active * * Don't remove it, but continueb instead */ break; } sendRemoveMarkers(signal, iter.curr.p); m_commitAckMarkerHash.release(iter.curr); break; } m_commitAckMarkerHash.next(iter); } signal->theData[0] = TcContinueB::ZHANDLE_FAILED_API_NODE_REMOVE_MARKERS; signal->theData[1] = nodeId; signal->theData[2] = iter.bucket; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); } void Dbtc::handleApiFailState(Signal* signal, UintR TapiConnectptr) { ApiConnectRecordPtr TlocalApiConnectptr; UintR TfailedApiNode; TlocalApiConnectptr.i = TapiConnectptr; ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord); TfailedApiNode = refToNode(TlocalApiConnectptr.p->ndbapiBlockref); arrGuard(TfailedApiNode, MAX_NODES); capiConnectClosing[TfailedApiNode]--; releaseApiCon(signal, TapiConnectptr); TlocalApiConnectptr.p->apiFailState = ZFALSE; if (capiConnectClosing[TfailedApiNode] == 0) { jam(); signal->theData[0] = TfailedApiNode; signal->theData[1] = cownref; sendSignal(capiFailRef, GSN_API_FAILCONF, signal, 2, JBB); }//if }//Dbtc::handleApiFailState() /**************************************************************************** * T C S E I Z E R E Q * THE APPLICATION SENDS A REQUEST TO SEIZE A CONNECT RECORD TO CARRY OUT A * TRANSACTION * TC BLOCK TAKE OUT A CONNECT RECORD FROM THE FREE LIST AND ESTABLISHES ALL * NECESSARY CONNECTION BEFORE REPLYING TO THE APPLICATION BLOCK ****************************************************************************/ void Dbtc::execTCSEIZEREQ(Signal* signal) { UintR tapiPointer; BlockReference tapiBlockref; /* SENDER BLOCK REFERENCE*/ jamEntry(); tapiPointer = signal->theData[0]; /* REQUEST SENDERS CONNECT RECORD POINTER*/ tapiBlockref = signal->theData[1]; /* SENDERS BLOCK REFERENCE*/ const NodeState::StartLevel sl = (NodeState::StartLevel)getNodeState().startLevel; const NodeId senderNodeId = refToNode(tapiBlockref); const bool local = senderNodeId == getOwnNodeId() || senderNodeId == 0; { { if (!(sl == NodeState::SL_STARTED || (sl == NodeState::SL_STARTING && local == true))) { jam(); Uint32 errCode = 0; if(!local) { switch(sl){ case NodeState::SL_STARTING: errCode = ZSYSTEM_NOT_STARTED_ERROR; break; case NodeState::SL_STOPPING_1: case NodeState::SL_STOPPING_2: if (getNodeState().getSingleUserMode()) break; case NodeState::SL_STOPPING_3: case NodeState::SL_STOPPING_4: if(getNodeState().stopping.systemShutdown) errCode = ZCLUSTER_SHUTDOWN_IN_PROGRESS; else errCode = ZNODE_SHUTDOWN_IN_PROGRESS; break; case NodeState::SL_SINGLEUSER: break; default: errCode = ZWRONG_STATE; break; } if (errCode) { signal->theData[0] = tapiPointer; signal->theData[1] = errCode; sendSignal(tapiBlockref, GSN_TCSEIZEREF, signal, 2, JBB); return; } }//if (!(sl == SL_SINGLEUSER)) } //if } } seizeApiConnect(signal); if (terrorCode == ZOK) { jam(); apiConnectptr.p->ndbapiConnect = tapiPointer; apiConnectptr.p->ndbapiBlockref = tapiBlockref; signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = apiConnectptr.i; sendSignal(tapiBlockref, GSN_TCSEIZECONF, signal, 2, JBB); return; } signal->theData[0] = tapiPointer; signal->theData[1] = terrorCode; sendSignal(tapiBlockref, GSN_TCSEIZEREF, signal, 2, JBB); }//Dbtc::execTCSEIZEREQ() /****************************************************************************/ /* T C R E L E A S E Q */ /* REQUEST TO RELEASE A CONNECT RECORD */ /****************************************************************************/ void Dbtc::execTCRELEASEREQ(Signal* signal) { UintR tapiPointer; BlockReference tapiBlockref; /* SENDER BLOCK REFERENCE*/ jamEntry(); tapiPointer = signal->theData[0]; /* REQUEST SENDERS CONNECT RECORD POINTER*/ tapiBlockref = signal->theData[1];/* SENDERS BLOCK REFERENCE*/ tuserpointer = signal->theData[2]; if (tapiPointer >= capiConnectFilesize) { jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; signal->theData[2] = __LINE__; sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 3, JBB); return; } else { jam(); apiConnectptr.i = tapiPointer; }//if ptrAss(apiConnectptr, apiConnectRecord); if (apiConnectptr.p->apiConnectstate == CS_DISCONNECTED) { jam(); signal->theData[0] = tuserpointer; sendSignal(tapiBlockref, GSN_TCRELEASECONF, signal, 1, JBB); } else { if (tapiBlockref == apiConnectptr.p->ndbapiBlockref) { if (apiConnectptr.p->apiConnectstate == CS_CONNECTED || (apiConnectptr.p->apiConnectstate == CS_ABORTING && apiConnectptr.p->abortState == AS_IDLE) || (apiConnectptr.p->apiConnectstate == CS_STARTED && apiConnectptr.p->firstTcConnect == RNIL)) { jam(); /* JUST REPLY OK */ apiConnectptr.p->m_transaction_nodes.clear(); releaseApiCon(signal, apiConnectptr.i); signal->theData[0] = tuserpointer; sendSignal(tapiBlockref, GSN_TCRELEASECONF, signal, 1, JBB); } else { jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; signal->theData[2] = __LINE__; signal->theData[3] = apiConnectptr.p->apiConnectstate; sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 4, JBB); } } else { jam(); signal->theData[0] = tuserpointer; signal->theData[1] = ZINVALID_CONNECTION; signal->theData[2] = __LINE__; signal->theData[3] = tapiBlockref; signal->theData[4] = apiConnectptr.p->ndbapiBlockref; sendSignal(tapiBlockref, GSN_TCRELEASEREF, signal, 5, JBB); }//if }//if }//Dbtc::execTCRELEASEREQ() /****************************************************************************/ // Error Handling for TCKEYREQ messages /****************************************************************************/ void Dbtc::signalErrorRefuseLab(Signal* signal) { ptrGuard(apiConnectptr); if (apiConnectptr.p->apiConnectstate != CS_DISCONNECTED) { jam(); apiConnectptr.p->abortState = AS_IDLE; apiConnectptr.p->apiConnectstate = CS_ABORTING; }//if sendSignalErrorRefuseLab(signal); }//Dbtc::signalErrorRefuseLab() void Dbtc::sendSignalErrorRefuseLab(Signal* signal) { ndbassert(false); ptrGuard(apiConnectptr); if (apiConnectptr.p->apiConnectstate != CS_DISCONNECTED) { jam(); ndbrequire(false); signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = signal->theData[ttransid_ptr]; signal->theData[2] = signal->theData[ttransid_ptr + 1]; signal->theData[3] = ZSIGNAL_ERROR; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREP, signal, 4, JBB); } }//Dbtc::sendSignalErrorRefuseLab() void Dbtc::abortBeginErrorLab(Signal* signal) { apiConnectptr.p->transid[0] = signal->theData[ttransid_ptr]; apiConnectptr.p->transid[1] = signal->theData[ttransid_ptr + 1]; abortErrorLab(signal); }//Dbtc::abortBeginErrorLab() void Dbtc::printState(Signal* signal, int place) { #ifdef VM_TRACE // Change to if 0 to disable these printouts ndbout << "-- Dbtc::printState -- " << endl; ndbout << "Received from place = " << place << " apiConnectptr.i = " << apiConnectptr.i << " apiConnectstate = " << apiConnectptr.p->apiConnectstate << endl; ndbout << "ctcTimer = " << ctcTimer << " ndbapiBlockref = " << hex <ndbapiBlockref << " Transid = " << apiConnectptr.p->transid[0] << " " << apiConnectptr.p->transid[1] << endl; ndbout << " apiTimer = " << getApiConTimer(apiConnectptr.i) << " counter = " << apiConnectptr.p->counter << " lqhkeyconfrec = " << apiConnectptr.p->lqhkeyconfrec << " lqhkeyreqrec = " << apiConnectptr.p->lqhkeyreqrec << endl; ndbout << "abortState = " << apiConnectptr.p->abortState << " apiScanRec = " << apiConnectptr.p->apiScanRec << " returncode = " << apiConnectptr.p->returncode << endl; ndbout << "tckeyrec = " << apiConnectptr.p->tckeyrec << " returnsignal = " << apiConnectptr.p->returnsignal << " apiFailState = " << apiConnectptr.p->apiFailState << endl; if (apiConnectptr.p->cachePtr != RNIL) { jam(); CacheRecord *localCacheRecord = cacheRecord; UintR TcacheFilesize = ccacheFilesize; UintR TcachePtr = apiConnectptr.p->cachePtr; if (TcachePtr < TcacheFilesize) { jam(); CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr]; ndbout << "currReclenAi = " << regCachePtr->currReclenAi << " attrlength = " << regCachePtr->attrlength << " tableref = " << regCachePtr->tableref << " keylen = " << regCachePtr->keylen << endl; } else { jam(); systemErrorLab(signal, __LINE__); }//if }//if #endif return; }//Dbtc::printState() void Dbtc::TCKEY_abort(Signal* signal, int place) { switch (place) { case 0: jam(); terrorCode = ZSTATE_ERROR; apiConnectptr.p->firstTcConnect = RNIL; printState(signal, 4); abortBeginErrorLab(signal); return; case 1: jam(); printState(signal, 3); sendSignalErrorRefuseLab(signal); return; case 2:{ printState(signal, 6); const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0]; const Uint32 t1 = tcKeyReq->transId1; const Uint32 t2 = tcKeyReq->transId2; signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = t1; signal->theData[2] = t2; signal->theData[3] = ZABORT_ERROR; ndbrequire(false); sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREP, signal, 4, JBB); return; } case 3: jam(); printState(signal, 7); noFreeConnectionErrorLab(signal); return; case 4: jam(); terrorCode = ZERO_KEYLEN_ERROR; releaseAtErrorLab(signal); return; case 5: jam(); terrorCode = ZNO_AI_WITH_UPDATE; releaseAtErrorLab(signal); return; case 6: jam(); warningHandlerLab(signal, __LINE__); return; case 7: jam(); tabStateErrorLab(signal); return; case 8: jam(); wrongSchemaVersionErrorLab(signal); return; case 9: jam(); terrorCode = ZSTATE_ERROR; releaseAtErrorLab(signal); return; case 10: jam(); systemErrorLab(signal, __LINE__); return; case 11: jam(); terrorCode = ZMORE_AI_IN_TCKEYREQ_ERROR; releaseAtErrorLab(signal); return; case 12: jam(); terrorCode = ZSIMPLE_READ_WITHOUT_AI; releaseAtErrorLab(signal); return; case 13: jam(); switch (tcConnectptr.p->tcConnectstate) { case OS_WAIT_KEYINFO: jam(); printState(signal, 8); terrorCode = ZSTATE_ERROR; abortErrorLab(signal); return; default: jam(); /********************************************************************/ /* MISMATCH BETWEEN STATE ON API CONNECTION AND THIS */ /* PARTICULAR TC CONNECT RECORD. THIS MUST BE CAUSED BY NDB */ /* INTERNAL ERROR. */ /********************************************************************/ systemErrorLab(signal, __LINE__); return; }//switch return; case 15: jam(); terrorCode = ZSCAN_NODE_ERROR; releaseAtErrorLab(signal); return; case 16: jam(); systemErrorLab(signal, __LINE__); return; case 17: jam(); systemErrorLab(signal, __LINE__); return; case 18: jam(); warningHandlerLab(signal, __LINE__); return; case 19: jam(); return; case 20: jam(); warningHandlerLab(signal, __LINE__); return; case 21: jam(); systemErrorLab(signal, __LINE__); return; case 22: jam(); systemErrorLab(signal, __LINE__); return; case 23: jam(); systemErrorLab(signal, __LINE__); return; case 24: jam(); seizeAttrbuferrorLab(signal); return; case 25: jam(); warningHandlerLab(signal, __LINE__); return; case 26: jam(); return; case 27: systemErrorLab(signal, __LINE__); jam(); return; case 28: jam(); // NOT USED return; case 29: jam(); systemErrorLab(signal, __LINE__); return; case 30: jam(); systemErrorLab(signal, __LINE__); return; case 31: jam(); systemErrorLab(signal, __LINE__); return; case 32: jam(); systemErrorLab(signal, __LINE__); return; case 33: jam(); systemErrorLab(signal, __LINE__); return; case 34: jam(); systemErrorLab(signal, __LINE__); return; case 35: jam(); systemErrorLab(signal, __LINE__); return; case 36: jam(); systemErrorLab(signal, __LINE__); return; case 37: jam(); systemErrorLab(signal, __LINE__); return; case 38: jam(); systemErrorLab(signal, __LINE__); return; case 39: jam(); systemErrorLab(signal, __LINE__); return; case 40: jam(); systemErrorLab(signal, __LINE__); return; case 41: jam(); systemErrorLab(signal, __LINE__); return; case 42: jam(); systemErrorLab(signal, __LINE__); return; case 43: jam(); systemErrorLab(signal, __LINE__); return; case 44: jam(); systemErrorLab(signal, __LINE__); return; case 45: jam(); systemErrorLab(signal, __LINE__); return; case 46: jam(); systemErrorLab(signal, __LINE__); return; case 47: jam(); terrorCode = apiConnectptr.p->returncode; releaseAtErrorLab(signal); return; case 48: jam(); terrorCode = ZCOMMIT_TYPE_ERROR; releaseAtErrorLab(signal); return; case 49: jam(); abortErrorLab(signal); return; case 50: jam(); systemErrorLab(signal, __LINE__); return; case 51: jam(); abortErrorLab(signal); return; case 52: jam(); abortErrorLab(signal); return; case 53: jam(); abortErrorLab(signal); return; case 54: jam(); abortErrorLab(signal); return; case 55: jam(); printState(signal, 5); sendSignalErrorRefuseLab(signal); return; case 56:{ jam(); terrorCode = ZNO_FREE_TC_MARKER; abortErrorLab(signal); return; } case 57:{ jam(); /** * Initialize object before starting error handling */ initApiConnectRec(signal, apiConnectptr.p, true); start_failure: switch(getNodeState().startLevel){ case NodeState::SL_STOPPING_2: if (getNodeState().getSingleUserMode()) { terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE; break; } case NodeState::SL_STOPPING_3: case NodeState::SL_STOPPING_4: if(getNodeState().stopping.systemShutdown) terrorCode = ZCLUSTER_SHUTDOWN_IN_PROGRESS; else terrorCode = ZNODE_SHUTDOWN_IN_PROGRESS; break; case NodeState::SL_SINGLEUSER: terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE; break; case NodeState::SL_STOPPING_1: if (getNodeState().getSingleUserMode()) { terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE; break; } default: terrorCode = ZWRONG_STATE; break; } abortErrorLab(signal); return; } case 58:{ jam(); releaseAtErrorLab(signal); return; } case 59:{ jam(); terrorCode = ZABORTINPROGRESS; abortErrorLab(signal); return; } case 60: { jam(); initApiConnectRec(signal, apiConnectptr.p, true); apiConnectptr.p->m_exec_flag = 1; goto start_failure; } default: jam(); systemErrorLab(signal, __LINE__); return; }//switch } static inline bool compare_transid(Uint32* val0, Uint32* val1) { Uint32 tmp0 = val0[0] ^ val1[0]; Uint32 tmp1 = val0[1] ^ val1[1]; return (tmp0 | tmp1) == 0; } void Dbtc::execKEYINFO(Signal* signal) { jamEntry(); apiConnectptr.i = signal->theData[0]; tmaxData = 20; if (apiConnectptr.i >= capiConnectFilesize) { TCKEY_abort(signal, 18); return; }//if ptrAss(apiConnectptr, apiConnectRecord); ttransid_ptr = 1; if (compare_transid(apiConnectptr.p->transid, signal->theData+1) == false) { TCKEY_abort(signal, 19); return; }//if switch (apiConnectptr.p->apiConnectstate) { case CS_RECEIVING: case CS_REC_COMMITTING: case CS_START_SCAN: jam(); /*empty*/; break; /* OK */ case CS_ABORTING: jam(); return; /* IGNORE */ case CS_CONNECTED: jam(); /****************************************************************>*/ /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */ /* SET STATE TO ABORTING. */ /****************************************************************>*/ printState(signal, 11); signalErrorRefuseLab(signal); return; case CS_STARTED: jam(); /****************************************************************>*/ /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */ /* SET STATE TO ABORTING. SINCE A TRANSACTION WAS STARTED */ /* WE ALSO NEED TO ABORT THIS TRANSACTION. */ /****************************************************************>*/ terrorCode = ZSIGNAL_ERROR; printState(signal, 2); abortErrorLab(signal); return; default: jam(); warningHandlerLab(signal, __LINE__); return; }//switch CacheRecord *localCacheRecord = cacheRecord; UintR TcacheFilesize = ccacheFilesize; UintR TcachePtr = apiConnectptr.p->cachePtr; UintR TtcTimer = ctcTimer; CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr]; if (TcachePtr >= TcacheFilesize) { TCKEY_abort(signal, 42); return; }//if setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); cachePtr.i = TcachePtr; cachePtr.p = regCachePtr; tcConnectptr.i = apiConnectptr.p->lastTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); switch (tcConnectptr.p->tcConnectstate) { case OS_WAIT_KEYINFO: jam(); tckeyreq020Lab(signal); return; case OS_WAIT_SCAN: break; default: jam(); terrorCode = ZSTATE_ERROR; abortErrorLab(signal); return; }//switch UintR TdataPos = 0; UintR TkeyLen = regCachePtr->keylen; UintR Tlen = regCachePtr->save1; do { if (cfirstfreeDatabuf == RNIL) { jam(); seizeDatabuferrorLab(signal); return; }//if linkKeybuf(signal); arrGuard(TdataPos, 19); databufptr.p->data[0] = signal->theData[TdataPos + 3]; databufptr.p->data[1] = signal->theData[TdataPos + 4]; databufptr.p->data[2] = signal->theData[TdataPos + 5]; databufptr.p->data[3] = signal->theData[TdataPos + 6]; Tlen = Tlen + 4; TdataPos = TdataPos + 4; if (Tlen < TkeyLen) { jam(); if (TdataPos >= tmaxData) { jam(); /*----------------------------------------------------*/ /** EXIT AND WAIT FOR SIGNAL KEYINFO OR KEYINFO9 **/ /** WHEN EITHER OF THE SIGNALS IS RECEIVED A JUMP **/ /** TO LABEL "KEYINFO_LABEL" IS DONE. THEN THE **/ /** PROGRAM RETURNS TO LABEL TCKEYREQ020 **/ /*----------------------------------------------------*/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); regCachePtr->save1 = Tlen; return; }//if } else { jam(); return; }//if } while (1); return; }//Dbtc::execKEYINFO() /*---------------------------------------------------------------------------*/ /* */ /* MORE THAN FOUR WORDS OF KEY DATA. WE NEED TO PACK THIS IN KEYINFO SIGNALS.*/ /* WE WILL ALWAYS PACK 4 WORDS AT A TIME. */ /*---------------------------------------------------------------------------*/ void Dbtc::packKeyData000Lab(Signal* signal, BlockReference TBRef, Uint32 totalLen) { CacheRecord * const regCachePtr = cachePtr.p; jam(); Uint32 len = 0; databufptr.i = regCachePtr->firstKeybuf; signal->theData[0] = tcConnectptr.i; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; Uint32 * dst = signal->theData+3; ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); do { jam(); databufptr.i = databufptr.p->nextDatabuf; dst[len + 0] = databufptr.p->data[0]; dst[len + 1] = databufptr.p->data[1]; dst[len + 2] = databufptr.p->data[2]; dst[len + 3] = databufptr.p->data[3]; len += 4; if (totalLen <= 4) { jam(); /*---------------------------------------------------------------------*/ /* LAST PACK OF KEY DATA HAVE BEEN SENT */ /*---------------------------------------------------------------------*/ /* THERE WERE UNSENT INFORMATION, SEND IT. */ /*---------------------------------------------------------------------*/ sendSignal(TBRef, GSN_KEYINFO, signal, 3 + len, JBB); return; } else if(len == KeyInfo::DataLength){ jam(); len = 0; sendSignal(TBRef, GSN_KEYINFO, signal, 3 + KeyInfo::DataLength, JBB); } totalLen -= 4; ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); } while (1); }//Dbtc::packKeyData000Lab() void Dbtc::tckeyreq020Lab(Signal* signal) { CacheRecord * const regCachePtr = cachePtr.p; UintR TdataPos = 0; UintR TkeyLen = regCachePtr->keylen; UintR Tlen = regCachePtr->save1; do { if (cfirstfreeDatabuf == RNIL) { jam(); seizeDatabuferrorLab(signal); return; }//if linkKeybuf(signal); arrGuard(TdataPos, 19); databufptr.p->data[0] = signal->theData[TdataPos + 3]; databufptr.p->data[1] = signal->theData[TdataPos + 4]; databufptr.p->data[2] = signal->theData[TdataPos + 5]; databufptr.p->data[3] = signal->theData[TdataPos + 6]; Tlen = Tlen + 4; TdataPos = TdataPos + 4; if (Tlen < TkeyLen) { jam(); if (TdataPos >= tmaxData) { jam(); /*----------------------------------------------------*/ /** EXIT AND WAIT FOR SIGNAL KEYINFO OR KEYINFO9 **/ /** WHEN EITHER OF THE SIGNALS IS RECEIVED A JUMP **/ /** TO LABEL "KEYINFO_LABEL" IS DONE. THEN THE **/ /** PROGRAM RETURNS TO LABEL TCKEYREQ020 **/ /*----------------------------------------------------*/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); regCachePtr->save1 = Tlen; tcConnectptr.p->tcConnectstate = OS_WAIT_KEYINFO; return; }//if } else { jam(); tckeyreq050Lab(signal); return; }//if } while (1); return; }//Dbtc::tckeyreq020Lab() /* ------------------------------------------------------------------------- */ /* ------- SAVE ATTRIBUTE INFORMATION IN OPERATION RECORD ------- */ /* ------------------------------------------------------------------------- */ void Dbtc::saveAttrbuf(Signal* signal) { CacheRecord * const regCachePtr = cachePtr.p; UintR TfirstfreeAttrbuf = cfirstfreeAttrbuf; UintR TattrbufFilesize = cattrbufFilesize; UintR TTcfirstAttrbuf = regCachePtr->firstAttrbuf; UintR Tlen = signal->length() - 3; AttrbufRecord *localAttrbufRecord = attrbufRecord; AttrbufRecord * const regAttrPtr = &localAttrbufRecord[TfirstfreeAttrbuf]; if (TfirstfreeAttrbuf >= TattrbufFilesize) { TCKEY_abort(signal, 21); return; }//if UintR Tnext = regAttrPtr->attrbuf[ZINBUF_NEXT]; if (TTcfirstAttrbuf == RNIL) { jam(); regCachePtr->firstAttrbuf = TfirstfreeAttrbuf; } else { AttrbufRecordPtr saAttrbufptr; saAttrbufptr.i = regCachePtr->lastAttrbuf; jam(); if (saAttrbufptr.i >= TattrbufFilesize) { TCKEY_abort(signal, 22); return; }//if saAttrbufptr.p = &localAttrbufRecord[saAttrbufptr.i]; saAttrbufptr.p->attrbuf[ZINBUF_NEXT] = TfirstfreeAttrbuf; }//if cfirstfreeAttrbuf = Tnext; regAttrPtr->attrbuf[ZINBUF_NEXT] = RNIL; regCachePtr->lastAttrbuf = TfirstfreeAttrbuf; regAttrPtr->attrbuf[ZINBUF_DATA_LEN] = Tlen; UintR Tdata1 = signal->theData[3]; UintR Tdata2 = signal->theData[4]; UintR Tdata3 = signal->theData[5]; UintR Tdata4 = signal->theData[6]; UintR Tdata5 = signal->theData[7]; UintR Tdata6 = signal->theData[8]; UintR Tdata7 = signal->theData[9]; UintR Tdata8 = signal->theData[10]; regAttrPtr->attrbuf[0] = Tdata1; regAttrPtr->attrbuf[1] = Tdata2; regAttrPtr->attrbuf[2] = Tdata3; regAttrPtr->attrbuf[3] = Tdata4; regAttrPtr->attrbuf[4] = Tdata5; regAttrPtr->attrbuf[5] = Tdata6; regAttrPtr->attrbuf[6] = Tdata7; regAttrPtr->attrbuf[7] = Tdata8; if (Tlen > 8) { Tdata1 = signal->theData[11]; Tdata2 = signal->theData[12]; Tdata3 = signal->theData[13]; Tdata4 = signal->theData[14]; Tdata5 = signal->theData[15]; Tdata6 = signal->theData[16]; Tdata7 = signal->theData[17]; regAttrPtr->attrbuf[8] = Tdata1; regAttrPtr->attrbuf[9] = Tdata2; regAttrPtr->attrbuf[10] = Tdata3; regAttrPtr->attrbuf[11] = Tdata4; regAttrPtr->attrbuf[12] = Tdata5; regAttrPtr->attrbuf[13] = Tdata6; regAttrPtr->attrbuf[14] = Tdata7; jam(); if (Tlen > 15) { Tdata1 = signal->theData[18]; Tdata2 = signal->theData[19]; Tdata3 = signal->theData[20]; Tdata4 = signal->theData[21]; Tdata5 = signal->theData[22]; Tdata6 = signal->theData[23]; Tdata7 = signal->theData[24]; jam(); regAttrPtr->attrbuf[15] = Tdata1; regAttrPtr->attrbuf[16] = Tdata2; regAttrPtr->attrbuf[17] = Tdata3; regAttrPtr->attrbuf[18] = Tdata4; regAttrPtr->attrbuf[19] = Tdata5; regAttrPtr->attrbuf[20] = Tdata6; regAttrPtr->attrbuf[21] = Tdata7; }//if }//if }//Dbtc::saveAttrbuf() void Dbtc::execATTRINFO(Signal* signal) { UintR Tdata1 = signal->theData[0]; UintR Tlength = signal->length(); UintR TapiConnectFilesize = capiConnectFilesize; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; jamEntry(); apiConnectptr.i = Tdata1; ttransid_ptr = 1; if (Tdata1 >= TapiConnectFilesize) { DEBUG("Drop ATTRINFO, wrong apiConnectptr"); TCKEY_abort(signal, 18); return; }//if ApiConnectRecord * const regApiPtr = &localApiConnectRecord[Tdata1]; apiConnectptr.p = regApiPtr; if (compare_transid(regApiPtr->transid, signal->theData+1) == false) { DEBUG("Drop ATTRINFO, wrong transid, lenght="<theData[1]<<", "<theData[2]); TCKEY_abort(signal, 19); return; }//if if (Tlength < 4) { DEBUG("Drop ATTRINFO, wrong length = " << Tlength); TCKEY_abort(signal, 20); return; } Tlength -= 3; UintR TcompREC_COMMIT = (regApiPtr->apiConnectstate == CS_REC_COMMITTING); UintR TcompRECEIVING = (regApiPtr->apiConnectstate == CS_RECEIVING); UintR TcompBOTH = TcompREC_COMMIT | TcompRECEIVING; if (TcompBOTH) { jam(); if (ERROR_INSERTED(8015)) { CLEAR_ERROR_INSERT_VALUE; return; }//if if (ERROR_INSERTED(8016)) { CLEAR_ERROR_INSERT_VALUE; return; }//if CacheRecord *localCacheRecord = cacheRecord; UintR TcacheFilesize = ccacheFilesize; UintR TcachePtr = regApiPtr->cachePtr; UintR TtcTimer = ctcTimer; CacheRecord * const regCachePtr = &localCacheRecord[TcachePtr]; if (TcachePtr >= TcacheFilesize) { TCKEY_abort(signal, 43); return; }//if UintR TfirstfreeAttrbuf = cfirstfreeAttrbuf; UintR TcurrReclenAi = regCachePtr->currReclenAi; UintR TattrLen = regCachePtr->attrlength; setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); cachePtr.i = TcachePtr; cachePtr.p = regCachePtr; TcurrReclenAi = TcurrReclenAi + Tlength; regCachePtr->currReclenAi = TcurrReclenAi; int TattrlengthRemain = TattrLen - TcurrReclenAi; if (TfirstfreeAttrbuf == RNIL) { DEBUG("No more attrinfo buffers"); TCKEY_abort(signal, 24); return; }//if saveAttrbuf(signal); if (TattrlengthRemain == 0) { /****************************************************************>*/ /* HERE WE HAVE FOUND THAT THE LAST SIGNAL BELONGING TO THIS */ /* OPERATION HAVE BEEN RECEIVED. THIS MEANS THAT WE CAN NOW REUSE */ /* THE API CONNECT RECORD. HOWEVER IF PREPARE OR COMMIT HAVE BEEN */ /* RECEIVED THEN IT IS NOT ALLOWED TO RECEIVE ANY FURTHER */ /* OPERATIONS. */ /****************************************************************>*/ UintR TlastConnect = regApiPtr->lastTcConnect; if (TcompRECEIVING) { jam(); regApiPtr->apiConnectstate = CS_STARTED; } else { jam(); regApiPtr->apiConnectstate = CS_START_COMMITTING; }//if tcConnectptr.i = TlastConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); attrinfoDihReceivedLab(signal); } else if (TattrlengthRemain < 0) { jam(); DEBUG("ATTRINFO wrong total length="<*/ /* MOST LIKELY CAUSED BY A MISSED SIGNAL. SEND REFUSE AND */ /* SET STATE TO ABORTING. SINCE A TRANSACTION WAS STARTED */ /* WE ALSO NEED TO ABORT THIS TRANSACTION. */ /****************************************************************>*/ terrorCode = ZSIGNAL_ERROR; printState(signal, 1); abortErrorLab(signal); return; default: jam(); /****************************************************************>*/ /* SIGNAL RECEIVED IN AN UNEXPECTED STATE. WE IGNORE SIGNAL */ /* SINCE WE DO NOT REALLY KNOW WHERE THE ERROR OCCURRED. */ /****************************************************************>*/ DEBUG("Drop ATTRINFO, illegal state="<apiConnectstate); printState(signal, 9); return; }//switch }//if }//Dbtc::execATTRINFO() /* *********************************************************************>> */ /* */ /* MODULE: HASH MODULE */ /* DESCRIPTION: CONTAINS THE HASH VALUE CALCULATION */ /* *********************************************************************> */ void Dbtc::hash(Signal* signal) { DatabufRecordPtr locDatabufptr; UintR ti; UintR Tdata0; UintR Tdata1; UintR Tdata2; UintR Tdata3; UintR* Tdata32; CacheRecord * const regCachePtr = cachePtr.p; Tdata32 = signal->theData; Tdata0 = regCachePtr->keydata[0]; Tdata1 = regCachePtr->keydata[1]; Tdata2 = regCachePtr->keydata[2]; Tdata3 = regCachePtr->keydata[3]; Tdata32[0] = Tdata0; Tdata32[1] = Tdata1; Tdata32[2] = Tdata2; Tdata32[3] = Tdata3; if (regCachePtr->keylen > 4) { locDatabufptr.i = regCachePtr->firstKeybuf; ti = 4; while (locDatabufptr.i != RNIL) { ptrCheckGuard(locDatabufptr, cdatabufFilesize, databufRecord); Tdata0 = locDatabufptr.p->data[0]; Tdata1 = locDatabufptr.p->data[1]; Tdata2 = locDatabufptr.p->data[2]; Tdata3 = locDatabufptr.p->data[3]; Tdata32[ti ] = Tdata0; Tdata32[ti + 1] = Tdata1; Tdata32[ti + 2] = Tdata2; Tdata32[ti + 3] = Tdata3; locDatabufptr.i = locDatabufptr.p->nextDatabuf; ti += 4; }//while }//if UintR keylen = (UintR)regCachePtr->keylen; Uint32 distKey = regCachePtr->distributionKeyIndicator; Uint32 tmp[4]; if(!regCachePtr->m_special_hash) { md5_hash(tmp, (Uint64*)&Tdata32[0], keylen); } else { handle_special_hash(tmp, Tdata32, keylen, regCachePtr->tableref, !distKey); } thashValue = tmp[0]; if (distKey){ jam(); tdistrHashValue = regCachePtr->distributionKey; } else { jam(); tdistrHashValue = tmp[1]; }//if }//Dbtc::hash() bool Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen, Uint32 tabPtrI, bool distr) { Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY]; const TableRecord* tabPtrP = &tableRecord[tabPtrI]; const bool hasVarKeys = tabPtrP->hasVarKeys; const bool hasCharAttr = tabPtrP->hasCharAttr; const bool compute_distkey = distr && (tabPtrP->noOfDistrKeys > 0); Uint32 *dst = (Uint32*)Tmp; Uint32 dstPos = 0; Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]; Uint32 * keyPartLenPtr; if(hasCharAttr || (compute_distkey && hasVarKeys)) { keyPartLenPtr = keyPartLen; dstPos = xfrm_key(tabPtrI, src, dst, sizeof(Tmp) >> 2, keyPartLenPtr); if (unlikely(dstPos == 0)) { goto error; } } else { dst = src; dstPos = srcLen; keyPartLenPtr = 0; } md5_hash(dstHash, (Uint64*)dst, dstPos); if(compute_distkey) { jam(); Uint32 tmp[4]; Uint32 len = create_distr_key(tabPtrI, dst, keyPartLenPtr); md5_hash(tmp, (Uint64*)dst, len); dstHash[1] = tmp[1]; } return true; // success error: terrorCode = ZINVALID_KEY; return false; } /* INIT_API_CONNECT_REC --------------------------- */ /* ========================================================================= */ /* ======= INIT_API_CONNECT_REC ======= */ /* */ /* ========================================================================= */ void Dbtc::initApiConnectRec(Signal* signal, ApiConnectRecord * const regApiPtr, bool releaseIndexOperations) { const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0]; UintR TfailureNr = cfailure_nr; UintR TtransCount = c_counters.ctransCount; UintR Ttransid0 = tcKeyReq->transId1; UintR Ttransid1 = tcKeyReq->transId2; regApiPtr->m_exec_flag = 0; regApiPtr->returncode = 0; regApiPtr->returnsignal = RS_TCKEYCONF; ndbassert(regApiPtr->firstTcConnect == RNIL); regApiPtr->firstTcConnect = RNIL; regApiPtr->lastTcConnect = RNIL; regApiPtr->globalcheckpointid = 0; regApiPtr->lqhkeyconfrec = 0; regApiPtr->lqhkeyreqrec = 0; regApiPtr->tckeyrec = 0; regApiPtr->tcindxrec = 0; regApiPtr->failureNr = TfailureNr; regApiPtr->transid[0] = Ttransid0; regApiPtr->transid[1] = Ttransid1; regApiPtr->commitAckMarker = RNIL; regApiPtr->buddyPtr = RNIL; regApiPtr->currSavePointId = 0; regApiPtr->m_transaction_nodes.clear(); regApiPtr->singleUserMode = 0; // Trigger data releaseFiredTriggerData(®ApiPtr->theFiredTriggers), // Index data regApiPtr->indexOpReturn = false; regApiPtr->noIndexOp = 0; if(releaseIndexOperations) releaseAllSeizedIndexOperations(regApiPtr); c_counters.ctransCount = TtransCount + 1; }//Dbtc::initApiConnectRec() int Dbtc::seizeTcRecord(Signal* signal) { ApiConnectRecord * const regApiPtr = apiConnectptr.p; TcConnectRecord *localTcConnectRecord = tcConnectRecord; UintR TfirstfreeTcConnect = cfirstfreeTcConnect; UintR TtcConnectFilesize = ctcConnectFilesize; tcConnectptr.i = TfirstfreeTcConnect; if (TfirstfreeTcConnect >= TtcConnectFilesize) { int place = 3; if (TfirstfreeTcConnect != RNIL) { place = 10; }//if TCKEY_abort(signal, place); return 1; }//if //-------------------------------------------------------------------------- // Optimised version of ptrAss(tcConnectptr, tcConnectRecord) //-------------------------------------------------------------------------- TcConnectRecord * const regTcPtr = &localTcConnectRecord[TfirstfreeTcConnect]; UintR TconcurrentOp = c_counters.cconcurrentOp; UintR TlastTcConnect = regApiPtr->lastTcConnect; UintR TtcConnectptrIndex = tcConnectptr.i; TcConnectRecordPtr tmpTcConnectptr; cfirstfreeTcConnect = regTcPtr->nextTcConnect; tcConnectptr.p = regTcPtr; c_counters.cconcurrentOp = TconcurrentOp + 1; regTcPtr->prevTcConnect = TlastTcConnect; regTcPtr->nextTcConnect = RNIL; regTcPtr->accumulatingTriggerData.i = RNIL; regTcPtr->accumulatingTriggerData.p = NULL; regTcPtr->noFiredTriggers = 0; regTcPtr->noReceivedTriggers = 0; regTcPtr->triggerExecutionCount = 0; regTcPtr->triggeringOperation = RNIL; regTcPtr->isIndexOp = false; regTcPtr->indexOp = RNIL; regTcPtr->currentIndexId = RNIL; regApiPtr->lastTcConnect = TtcConnectptrIndex; if (TlastTcConnect == RNIL) { jam(); regApiPtr->firstTcConnect = TtcConnectptrIndex; } else { tmpTcConnectptr.i = TlastTcConnect; jam(); ptrCheckGuard(tmpTcConnectptr, TtcConnectFilesize, localTcConnectRecord); tmpTcConnectptr.p->nextTcConnect = TtcConnectptrIndex; }//if return 0; }//Dbtc::seizeTcRecord() int Dbtc::seizeCacheRecord(Signal* signal) { ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TfirstfreeCacheRec = cfirstfreeCacheRec; UintR TcacheFilesize = ccacheFilesize; CacheRecord *localCacheRecord = cacheRecord; if (TfirstfreeCacheRec >= TcacheFilesize) { TCKEY_abort(signal, 41); return 1; }//if CacheRecord * const regCachePtr = &localCacheRecord[TfirstfreeCacheRec]; regApiPtr->cachePtr = TfirstfreeCacheRec; cfirstfreeCacheRec = regCachePtr->nextCacheRec; cachePtr.i = TfirstfreeCacheRec; cachePtr.p = regCachePtr; #ifdef VM_TRACE // This is a good place to check that resources have // been properly released from CacheRecord ndbrequire(regCachePtr->firstKeybuf == RNIL); ndbrequire(regCachePtr->lastKeybuf == RNIL); #endif regCachePtr->firstKeybuf = RNIL; regCachePtr->lastKeybuf = RNIL; regCachePtr->firstAttrbuf = RNIL; regCachePtr->lastAttrbuf = RNIL; regCachePtr->currReclenAi = 0; return 0; }//Dbtc::seizeCacheRecord() /*****************************************************************************/ /* T C K E Y R E Q */ /* AFTER HAVING ESTABLISHED THE CONNECT, THE APPLICATION BLOCK SENDS AN */ /* OPERATION REQUEST TO TC. ALL NECESSARY INFORMATION TO CARRY OUT REQUEST */ /* IS FURNISHED IN PARAMETERS. TC STORES THIS INFORMATION AND ENQUIRES */ /* FROM DIH ABOUT THE NODES WHICH MAY HAVE THE REQUESTED DATA */ /*****************************************************************************/ void Dbtc::execTCKEYREQ(Signal* signal) { Uint32 sendersNodeId = refToNode(signal->getSendersBlockRef()); UintR compare_transid1, compare_transid2; UintR titcLenAiInTckeyreq; UintR TkeyLength; const TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtr(); UintR Treqinfo; jamEntry(); /*------------------------------------------------------------------------- * Common error routines are used for several signals, they need to know * where to find the transaction identifier in the signal. *-------------------------------------------------------------------------*/ const UintR TapiIndex = tcKeyReq->apiConnectPtr; const UintR TapiMaxIndex = capiConnectFilesize; const UintR TtabIndex = tcKeyReq->tableId; const UintR TtabMaxIndex = ctabrecFilesize; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; ttransid_ptr = 6; apiConnectptr.i = TapiIndex; if (TapiIndex >= TapiMaxIndex) { TCKEY_abort(signal, 6); return; }//if if (TtabIndex >= TtabMaxIndex) { TCKEY_abort(signal, 7); return; }//if Treqinfo = tcKeyReq->requestInfo; //-------------------------------------------------------------------------- // Optimised version of ptrAss(tabptr, tableRecord) // Optimised version of ptrAss(apiConnectptr, apiConnectRecord) //-------------------------------------------------------------------------- ApiConnectRecord * const regApiPtr = &localApiConnectRecord[TapiIndex]; apiConnectptr.p = regApiPtr; Uint32 TstartFlag = TcKeyReq::getStartFlag(Treqinfo); Uint32 TexecFlag = TcKeyReq::getExecuteFlag(Treqinfo); Uint8 isIndexOp = regApiPtr->isIndexOp; bool isIndexOpReturn = regApiPtr->indexOpReturn; regApiPtr->isIndexOp = false; // Reset marker regApiPtr->m_exec_flag |= TexecFlag; TableRecordPtr localTabptr; localTabptr.i = TtabIndex; localTabptr.p = &tableRecord[TtabIndex]; switch (regApiPtr->apiConnectstate) { case CS_CONNECTED:{ if (TstartFlag == 1 && getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == true){ //--------------------------------------------------------------------- // Initialise API connect record if transaction is started. //--------------------------------------------------------------------- jam(); initApiConnectRec(signal, regApiPtr); regApiPtr->m_exec_flag = TexecFlag; } else { if(getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == true){ /*------------------------------------------------------------------ * WE EXPECTED A START TRANSACTION. SINCE NO OPERATIONS HAVE BEEN * RECEIVED WE INDICATE THIS BY SETTING FIRST_TC_CONNECT TO RNIL TO * ENSURE PROPER OPERATION OF THE COMMON ABORT HANDLING. *-----------------------------------------------------------------*/ TCKEY_abort(signal, 0); return; } else { /** * getAllowStartTransaction(sendersNodeId) == false */ TCKEY_abort(signal, TexecFlag ? 60 : 57); return; }//if } } break; case CS_STARTED: if(TstartFlag == 1 && regApiPtr->firstTcConnect == RNIL) { /** * If last operation in last transaction was a simple/dirty read * it does not have to be committed or rollbacked hence, * the state will be CS_STARTED */ jam(); if (unlikely(getNodeState().getSingleUserMode()) && getNodeState().getSingleUserApi() != sendersNodeId && !localTabptr.p->singleUserMode) { TCKEY_abort(signal, TexecFlag ? 60 : 57); return; } initApiConnectRec(signal, regApiPtr); regApiPtr->m_exec_flag = TexecFlag; } else { //---------------------------------------------------------------------- // Transaction is started already. // Check that the operation is on the same transaction. //----------------------------------------------------------------------- compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1; compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2; jam(); compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { TCKEY_abort(signal, 1); return; }//if } break; case CS_ABORTING: if (regApiPtr->abortState == AS_IDLE) { if (TstartFlag == 1) { if(getAllowStartTransaction(sendersNodeId, localTabptr.p->singleUserMode) == false){ TCKEY_abort(signal, TexecFlag ? 60 : 57); return; } //-------------------------------------------------------------------- // Previous transaction had been aborted and the abort was completed. // It is then OK to start a new transaction again. //-------------------------------------------------------------------- jam(); initApiConnectRec(signal, regApiPtr); regApiPtr->m_exec_flag = TexecFlag; } else if(TexecFlag) { TCKEY_abort(signal, 59); return; } else { //-------------------------------------------------------------------- // The current transaction was aborted successfully. // We will not do anything before we receive an operation // with a start indicator. We will ignore this signal. //-------------------------------------------------------------------- jam(); DEBUG("Drop TCKEYREQ - apiConnectState=CS_ABORTING, ==AS_IDLE"); return; }//if } else { //---------------------------------------------------------------------- // Previous transaction is still aborting //---------------------------------------------------------------------- jam(); if (TstartFlag == 1) { //-------------------------------------------------------------------- // If a new transaction tries to start while the old is // still aborting, we will report this to the starting API. //-------------------------------------------------------------------- TCKEY_abort(signal, 2); return; } else if(TexecFlag) { TCKEY_abort(signal, 59); return; } //---------------------------------------------------------------------- // Ignore signals without start indicator set when aborting transaction. //---------------------------------------------------------------------- DEBUG("Drop TCKEYREQ - apiConnectState=CS_ABORTING, !=AS_IDLE"); return; }//if break; case CS_START_COMMITTING: jam(); if(isIndexOpReturn || TcKeyReq::getExecutingTrigger(Treqinfo)){ break; } default: jam(); /*---------------------------------------------------------------------- * IN THIS CASE THE NDBAPI IS AN UNTRUSTED ENTITY THAT HAS SENT A SIGNAL * WHEN IT WAS NOT EXPECTED TO. * WE MIGHT BE IN A PROCESS TO RECEIVE, PREPARE, * COMMIT OR COMPLETE AND OBVIOUSLY THIS IS NOT A DESIRED EVENT. * WE WILL ALWAYS COMPLETE THE ABORT HANDLING BEFORE WE ALLOW * ANYTHING TO HAPPEN ON THIS CONNECTION AGAIN. * THUS THERE IS NO ACTION FROM THE API THAT CAN SPEED UP THIS PROCESS. *---------------------------------------------------------------------*/ TCKEY_abort(signal, 55); return; }//switch if (localTabptr.p->checkTable(tcKeyReq->tableSchemaVersion)) { ; } else { /*-----------------------------------------------------------------------*/ /* THE API IS WORKING WITH AN OLD SCHEMA VERSION. IT NEEDS REPLACEMENT. */ /* COULD ALSO BE THAT THE TABLE IS NOT DEFINED. */ /*-----------------------------------------------------------------------*/ TCKEY_abort(signal, 8); return; }//if //------------------------------------------------------------------------- // Error Insertion for testing purposes. Test to see what happens when no // more TC records available. //------------------------------------------------------------------------- if (ERROR_INSERTED(8032)) { TCKEY_abort(signal, 3); return; }//if if (seizeTcRecord(signal) != 0) { return; }//if if (seizeCacheRecord(signal) != 0) { return; }//if TcConnectRecord * const regTcPtr = tcConnectptr.p; CacheRecord * const regCachePtr = cachePtr.p; /* INIT_TC_CONNECT_REC ------------------------- */ /* ---------------------------------------------------------------------- */ /* ------- INIT OPERATION RECORD WITH SIGNAL DATA AND RNILS ------- */ /* */ /* ---------------------------------------------------------------------- */ UintR TapiVersionNo = TcKeyReq::getAPIVersion(tcKeyReq->attrLen); UintR Tlqhkeyreqrec = regApiPtr->lqhkeyreqrec; regApiPtr->lqhkeyreqrec = Tlqhkeyreqrec + 1; regCachePtr->apiVersionNo = TapiVersionNo; UintR TapiConnectptrIndex = apiConnectptr.i; UintR TsenderData = tcKeyReq->senderData; UintR TattrLen = TcKeyReq::getAttrinfoLen(tcKeyReq->attrLen); UintR TattrinfoCount = c_counters.cattrinfoCount; regTcPtr->apiConnect = TapiConnectptrIndex; regTcPtr->clientData = TsenderData; regTcPtr->commitAckMarker = RNIL; regTcPtr->isIndexOp = isIndexOp; regTcPtr->indexOp = regApiPtr->executingIndexOp; regTcPtr->savePointId = regApiPtr->currSavePointId; regApiPtr->executingIndexOp = RNIL; regApiPtr->singleUserMode |= 1 << localTabptr.p->singleUserMode; if (TcKeyReq::getExecutingTrigger(Treqinfo)) { // Save the TcOperationPtr for fireing operation regTcPtr->triggeringOperation = TsenderData; } if (TexecFlag){ Uint32 currSPId = regApiPtr->currSavePointId; regApiPtr->currSavePointId = ++currSPId; } regCachePtr->attrlength = TattrLen; c_counters.cattrinfoCount = TattrinfoCount + TattrLen; UintR TtabptrIndex = localTabptr.i; UintR TtableSchemaVersion = tcKeyReq->tableSchemaVersion; Uint8 TOperationType = TcKeyReq::getOperationType(Treqinfo); regCachePtr->tableref = TtabptrIndex; regCachePtr->schemaVersion = TtableSchemaVersion; regTcPtr->operation = TOperationType; Uint8 TSimpleFlag = TcKeyReq::getSimpleFlag(Treqinfo); Uint8 TDirtyFlag = TcKeyReq::getDirtyFlag(Treqinfo); Uint8 TInterpretedFlag = TcKeyReq::getInterpretedFlag(Treqinfo); Uint8 TDistrKeyFlag = TcKeyReq::getDistributionKeyFlag(Treqinfo); Uint8 TNoDiskFlag = TcKeyReq::getNoDiskFlag(Treqinfo); Uint8 TexecuteFlag = TexecFlag; regTcPtr->dirtyOp = TDirtyFlag; regTcPtr->opSimple = TSimpleFlag; regCachePtr->opExec = TInterpretedFlag; regCachePtr->distributionKeyIndicator = TDistrKeyFlag; regCachePtr->m_no_disk_flag = TNoDiskFlag; //------------------------------------------------------------- // The next step is to read the upto three conditional words. //------------------------------------------------------------- Uint32 TkeyIndex; Uint32* TOptionalDataPtr = (Uint32*)&tcKeyReq->scanInfo; { Uint32 TDistrGHIndex = TcKeyReq::getScanIndFlag(Treqinfo); Uint32 TDistrKeyIndex = TDistrGHIndex; Uint32 TscanInfo = TcKeyReq::getTakeOverScanInfo(TOptionalDataPtr[0]); regCachePtr->scanTakeOverInd = TDistrGHIndex; regCachePtr->scanInfo = TscanInfo; regCachePtr->distributionKey = TOptionalDataPtr[TDistrKeyIndex]; TkeyIndex = TDistrKeyIndex + TDistrKeyFlag; } Uint32* TkeyDataPtr = &TOptionalDataPtr[TkeyIndex]; UintR Tdata1 = TkeyDataPtr[0]; UintR Tdata2 = TkeyDataPtr[1]; UintR Tdata3 = TkeyDataPtr[2]; UintR Tdata4 = TkeyDataPtr[3]; UintR Tdata5; regCachePtr->keydata[0] = Tdata1; regCachePtr->keydata[1] = Tdata2; regCachePtr->keydata[2] = Tdata3; regCachePtr->keydata[3] = Tdata4; TkeyLength = TcKeyReq::getKeyLength(Treqinfo); Uint32 TAIDataIndex; if (TkeyLength > 8) { TAIDataIndex = TkeyIndex + 8; } else { if (TkeyLength == 0) { TCKEY_abort(signal, 4); return; }//if TAIDataIndex = TkeyIndex + TkeyLength; }//if Uint32* TAIDataPtr = &TOptionalDataPtr[TAIDataIndex]; titcLenAiInTckeyreq = TcKeyReq::getAIInTcKeyReq(Treqinfo); regCachePtr->keylen = TkeyLength; regCachePtr->lenAiInTckeyreq = titcLenAiInTckeyreq; regCachePtr->currReclenAi = titcLenAiInTckeyreq; regCachePtr->m_special_hash = localTabptr.p->hasCharAttr | (localTabptr.p->noOfDistrKeys > 0); Tdata1 = TAIDataPtr[0]; Tdata2 = TAIDataPtr[1]; Tdata3 = TAIDataPtr[2]; Tdata4 = TAIDataPtr[3]; Tdata5 = TAIDataPtr[4]; regCachePtr->attrinfo0 = Tdata1; regCachePtr->attrinfo15[0] = Tdata2; regCachePtr->attrinfo15[1] = Tdata3; regCachePtr->attrinfo15[2] = Tdata4; regCachePtr->attrinfo15[3] = Tdata5; if (TOperationType == ZREAD || TOperationType == ZREAD_EX) { Uint32 TreadCount = c_counters.creadCount; jam(); c_counters.creadCount = TreadCount + 1; } else { if(regApiPtr->commitAckMarker == RNIL){ jam(); CommitAckMarkerPtr tmp; if(!m_commitAckMarkerHash.seize(tmp)){ TCKEY_abort(signal, 56); return; } else { regTcPtr->commitAckMarker = tmp.i; regApiPtr->commitAckMarker = tmp.i; tmp.p->transid1 = tcKeyReq->transId1; tmp.p->transid2 = tcKeyReq->transId2; tmp.p->apiNodeId = refToNode(regApiPtr->ndbapiBlockref); tmp.p->apiConnectPtr = TapiIndex; tmp.p->noOfLqhs = 0; #if defined VM_TRACE || defined ERROR_INSERT { CommitAckMarkerPtr check; ndbrequire(!m_commitAckMarkerHash.find(check, *tmp.p)); } #endif m_commitAckMarkerHash.add(tmp); } } UintR TwriteCount = c_counters.cwriteCount; UintR Toperationsize = coperationsize; /* -------------------------------------------------------------------- * THIS IS A TEMPORARY TABLE, DON'T UPDATE coperationsize. * THIS VARIABLE CONTROLS THE INTERVAL BETWEEN LCP'S AND * TEMP TABLES DON'T PARTICIPATE. * -------------------------------------------------------------------- */ if (localTabptr.p->get_storedTable()) { coperationsize = ((Toperationsize + TattrLen) + TkeyLength) + 17; } c_counters.cwriteCount = TwriteCount + 1; switch (TOperationType) { case ZUPDATE: case ZINSERT: case ZDELETE: case ZWRITE: jam(); break; default: TCKEY_abort(signal, 9); return; }//switch }//if Uint32 TabortOption = TcKeyReq::getAbortOption(Treqinfo); regTcPtr->m_execAbortOption = TabortOption; /*------------------------------------------------------------------------- * Check error handling per operation * If CommitFlag is set state accordingly and check for early abort *------------------------------------------------------------------------*/ if (TcKeyReq::getCommitFlag(Treqinfo) == 1) { ndbrequire(TexecuteFlag); regApiPtr->apiConnectstate = CS_REC_COMMITTING; } else { /* --------------------------------------------------------------------- * PREPARE TRANSACTION IS NOT IMPLEMENTED YET. * --------------------------------------------------------------------- * ELSIF (TREQINFO => 3) (*) 1 = 1 THEN * IF PREPARE TRANSACTION THEN * API_CONNECTPTR:API_CONNECTSTATE = REC_PREPARING * SET STATE TO PREPARING * --------------------------------------------------------------------- */ if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { jam(); // Trigger execution at commit regApiPtr->apiConnectstate = CS_REC_COMMITTING; } else { jam(); regApiPtr->apiConnectstate = CS_RECEIVING; }//if }//if if (TkeyLength <= 4) { tckeyreq050Lab(signal); return; } else { if (cfirstfreeDatabuf != RNIL) { jam(); linkKeybuf(signal); Tdata1 = TkeyDataPtr[4]; Tdata2 = TkeyDataPtr[5]; Tdata3 = TkeyDataPtr[6]; Tdata4 = TkeyDataPtr[7]; DatabufRecord * const regDataPtr = databufptr.p; regDataPtr->data[0] = Tdata1; regDataPtr->data[1] = Tdata2; regDataPtr->data[2] = Tdata3; regDataPtr->data[3] = Tdata4; } else { jam(); seizeDatabuferrorLab(signal); return; }//if if (TkeyLength <= 8) { jam(); tckeyreq050Lab(signal); return; } else { jam(); /* -------------------------------------------------------------------- * THE TCKEYREQ DIDN'T CONTAIN ALL KEY DATA, * SAVE STATE AND WAIT FOR KEYINFO * --------------------------------------------------------------------*/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); regCachePtr->save1 = 8; regTcPtr->tcConnectstate = OS_WAIT_KEYINFO; return; }//if }//if return; }//Dbtc::execTCKEYREQ() void Dbtc::tckeyreq050Lab(Signal* signal) { UintR tnoOfBackup; UintR tnoOfStandby; UintR tnodeinfo; terrorCode = 0; hash(signal); /* NOW IT IS TIME TO CALCULATE THE HASH VALUE*/ if (unlikely(terrorCode)) { releaseAtErrorLab(signal); return; } CacheRecord * const regCachePtr = cachePtr.p; TcConnectRecord * const regTcPtr = tcConnectptr.p; ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TtcTimer = ctcTimer; UintR ThashValue = thashValue; UintR TdistrHashValue = tdistrHashValue; UintR TdihConnectptr = regTcPtr->dihConnectptr; UintR Ttableref = regCachePtr->tableref; TableRecordPtr localTabptr; localTabptr.i = Ttableref; localTabptr.p = &tableRecord[localTabptr.i]; Uint32 schemaVersion = regCachePtr->schemaVersion; if(localTabptr.p->checkTable(schemaVersion)){ ; } else { terrorCode = localTabptr.p->getErrorCode(schemaVersion); TCKEY_abort(signal, 58); return; } setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); regCachePtr->hashValue = ThashValue; signal->theData[0] = TdihConnectptr; signal->theData[1] = Ttableref; signal->theData[2] = TdistrHashValue; signal->theData[3] = 0; signal->theData[4] = 0; signal->theData[5] = 0; signal->theData[6] = 0; /*-------------------------------------------------------------*/ /* FOR EFFICIENCY REASONS WE AVOID THE SIGNAL SENDING HERE AND */ /* PROCEED IMMEDIATELY TO DIH. IN MULTI-THREADED VERSIONS WE */ /* HAVE TO INSERT A MUTEX ON DIH TO ENSURE PROPER OPERATION. */ /* SINCE THIS SIGNAL AND DIVERIFYREQ ARE THE ONLY SIGNALS SENT */ /* TO DIH IN TRAFFIC IT SHOULD BE OK (3% OF THE EXECUTION TIME */ /* IS SPENT IN DIH AND EVEN LESS IN REPLICATED NDB. */ /*-------------------------------------------------------------*/ EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal, 3); UintR TerrorIndicator = signal->theData[0]; jamEntry(); if (TerrorIndicator != 0) { execDIGETNODESREF(signal); return; } if(ERROR_INSERTED(8050) && signal->theData[3] != getOwnNodeId()) { ndbassert(false); signal->theData[1] = 626; execDIGETNODESREF(signal); return; } /****************>>*/ /* DIGETNODESCONF >*/ /* ***************>*/ UintR Tdata1 = signal->theData[1]; UintR Tdata2 = signal->theData[2]; UintR Tdata3 = signal->theData[3]; UintR Tdata4 = signal->theData[4]; UintR Tdata5 = signal->theData[5]; UintR Tdata6 = signal->theData[6]; regCachePtr->fragmentid = Tdata1; tnodeinfo = Tdata2; regTcPtr->tcNodedata[0] = Tdata3; regTcPtr->tcNodedata[1] = Tdata4; regTcPtr->tcNodedata[2] = Tdata5; regTcPtr->tcNodedata[3] = Tdata6; Uint8 Toperation = regTcPtr->operation; Uint8 Tdirty = regTcPtr->dirtyOp; tnoOfBackup = tnodeinfo & 3; tnoOfStandby = (tnodeinfo >> 8) & 3; regCachePtr->fragmentDistributionKey = (tnodeinfo >> 16) & 255; if (Toperation == ZREAD || Toperation == ZREAD_EX) { if (Tdirty == 1) { jam(); /*-------------------------------------------------------------*/ /* A SIMPLE READ CAN SELECT ANY OF THE PRIMARY AND */ /* BACKUP NODES TO READ. WE WILL TRY TO SELECT THIS */ /* NODE IF POSSIBLE TO AVOID UNNECESSARY COMMUNICATION */ /* WITH SIMPLE READS. */ /*-------------------------------------------------------------*/ arrGuard(tnoOfBackup, MAX_REPLICAS); UintR Tindex; UintR TownNode = cownNodeid; for (Tindex = 1; Tindex <= tnoOfBackup; Tindex++) { UintR Tnode = regTcPtr->tcNodedata[Tindex]; jam(); if (Tnode == TownNode) { jam(); regTcPtr->tcNodedata[0] = Tnode; }//if }//for if(ERROR_INSERTED(8048) || ERROR_INSERTED(8049)) { for (Tindex = 0; Tindex <= tnoOfBackup; Tindex++) { UintR Tnode = regTcPtr->tcNodedata[Tindex]; jam(); if (Tnode != TownNode) { jam(); regTcPtr->tcNodedata[0] = Tnode; ndbout_c("Choosing %d", Tnode); }//if }//for } }//if jam(); regTcPtr->lastReplicaNo = 0; regTcPtr->noOfNodes = 1; } else { UintR TlastReplicaNo; jam(); TlastReplicaNo = tnoOfBackup + tnoOfStandby; regTcPtr->lastReplicaNo = (Uint8)TlastReplicaNo; regTcPtr->noOfNodes = (Uint8)(TlastReplicaNo + 1); }//if if (regCachePtr->lenAiInTckeyreq == regCachePtr->attrlength) { /****************************************************************>*/ /* HERE WE HAVE FOUND THAT THE LAST SIGNAL BELONGING TO THIS */ /* OPERATION HAVE BEEN RECEIVED. THIS MEANS THAT WE CAN NOW REUSE */ /* THE API CONNECT RECORD. HOWEVER IF PREPARE OR COMMIT HAVE BEEN */ /* RECEIVED THEN IT IS NOT ALLOWED TO RECEIVE ANY FURTHER */ /* OPERATIONS. WE KNOW THAT WE WILL WAIT FOR DICT NEXT. IT IS NOT */ /* POSSIBLE FOR THE TC CONNECTION TO BE READY YET. */ /****************************************************************>*/ switch (regApiPtr->apiConnectstate) { case CS_RECEIVING: jam(); regApiPtr->apiConnectstate = CS_STARTED; break; case CS_REC_COMMITTING: jam(); regApiPtr->apiConnectstate = CS_START_COMMITTING; break; default: jam(); systemErrorLab(signal, __LINE__); return; }//switch attrinfoDihReceivedLab(signal); return; } else { if (regCachePtr->lenAiInTckeyreq < regCachePtr->attrlength) { TtcTimer = ctcTimer; jam(); setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); regTcPtr->tcConnectstate = OS_WAIT_ATTR; return; } else { TCKEY_abort(signal, 11); return; }//if }//if return; }//Dbtc::tckeyreq050Lab() void Dbtc::attrinfoDihReceivedLab(Signal* signal) { CacheRecord * const regCachePtr = cachePtr.p; TcConnectRecord * const regTcPtr = tcConnectptr.p; Uint16 Tnode = regTcPtr->tcNodedata[0]; TableRecordPtr localTabptr; localTabptr.i = regCachePtr->tableref; localTabptr.p = &tableRecord[localTabptr.i]; if(localTabptr.p->checkTable(regCachePtr->schemaVersion)){ ; } else { terrorCode = localTabptr.p->getErrorCode(regCachePtr->schemaVersion); TCKEY_abort(signal, 58); return; } arrGuard(Tnode, MAX_NDB_NODES); packLqhkeyreq(signal, calcLqhBlockRef(Tnode)); }//Dbtc::attrinfoDihReceivedLab() void Dbtc::packLqhkeyreq(Signal* signal, BlockReference TBRef) { CacheRecord * const regCachePtr = cachePtr.p; UintR Tkeylen = regCachePtr->keylen; UintR TfirstAttrbuf = regCachePtr->firstAttrbuf; sendlqhkeyreq(signal, TBRef); if (Tkeylen > 4) { packKeyData000Lab(signal, TBRef, Tkeylen - 4); releaseKeys(); }//if packLqhkeyreq040Lab(signal, TfirstAttrbuf, TBRef); }//Dbtc::packLqhkeyreq() void Dbtc::sendlqhkeyreq(Signal* signal, BlockReference TBRef) { UintR tslrAttrLen; UintR Tdata10; TcConnectRecord * const regTcPtr = tcConnectptr.p; ApiConnectRecord * const regApiPtr = apiConnectptr.p; CacheRecord * const regCachePtr = cachePtr.p; Uint32 version = getNodeInfo(refToNode(TBRef)).m_version; UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6; #ifdef ERROR_INSERT if (ERROR_INSERTED(8002)) { systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8007)) { if (apiConnectptr.p->apiConnectstate == CS_STARTED) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8008)) { if (apiConnectptr.p->apiConnectstate == CS_START_COMMITTING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8009)) { if (apiConnectptr.p->apiConnectstate == CS_STARTED) { return; }//if }//if if (ERROR_INSERTED(8010)) { if (apiConnectptr.p->apiConnectstate == CS_START_COMMITTING) { return; }//if }//if #endif tslrAttrLen = 0; LqhKeyReq::setAttrLen(tslrAttrLen, regCachePtr->attrlength); /* ---------------------------------------------------------------------- */ // Bit16 == 0 since StoredProcedures are not yet supported. /* ---------------------------------------------------------------------- */ LqhKeyReq::setDistributionKey(tslrAttrLen, regCachePtr->fragmentDistributionKey); LqhKeyReq::setScanTakeOverFlag(tslrAttrLen, regCachePtr->scanTakeOverInd); Tdata10 = 0; sig0 = regTcPtr->opSimple; sig1 = regTcPtr->operation; sig2 = regTcPtr->dirtyOp; bool dirtyRead = (sig1 == ZREAD && sig2 == ZTRUE); LqhKeyReq::setKeyLen(Tdata10, regCachePtr->keylen); LqhKeyReq::setLastReplicaNo(Tdata10, regTcPtr->lastReplicaNo); if (unlikely(version < NDBD_ROWID_VERSION)) { Uint32 op = regTcPtr->operation; Uint32 lock = (Operation_t) op == ZREAD_EX ? ZUPDATE : (Operation_t) op == ZWRITE ? ZINSERT : (Operation_t) op; LqhKeyReq::setLockType(Tdata10, lock); } /* ---------------------------------------------------------------------- */ // Indicate Application Reference is present in bit 15 /* ---------------------------------------------------------------------- */ LqhKeyReq::setApplicationAddressFlag(Tdata10, 1); LqhKeyReq::setDirtyFlag(Tdata10, sig2); LqhKeyReq::setInterpretedFlag(Tdata10, regCachePtr->opExec); LqhKeyReq::setSimpleFlag(Tdata10, sig0); LqhKeyReq::setOperation(Tdata10, sig1); LqhKeyReq::setNoDiskFlag(Tdata10, regCachePtr->m_no_disk_flag); /* ----------------------------------------------------------------------- * Sequential Number of first LQH = 0, bit 22-23 * IF ATTRIBUTE INFORMATION IS SENT IN TCKEYREQ, * IT IS ALSO SENT IN LQHKEYREQ * ----------------------------------------------------------------------- */ LqhKeyReq::setAIInLqhKeyReq(Tdata10, regCachePtr->lenAiInTckeyreq); /* ----------------------------------------------------------------------- * Bit 27 == 0 since TC record is the same as the client record. * Bit 28 == 0 since readLenAi can only be set after reading in LQH. * ----------------------------------------------------------------------- */ //LqhKeyReq::setAPIVersion(Tdata10, regCachePtr->apiVersionNo); Uint32 commitAckMarker = regTcPtr->commitAckMarker; const Uint32 noOfLqhs = regTcPtr->noOfNodes; if(commitAckMarker != RNIL){ jam(); LqhKeyReq::setMarkerFlag(Tdata10, 1); CommitAckMarker * tmp = m_commitAckMarkerHash.getPtr(commitAckMarker); /** * Populate LQH array */ tmp->noOfLqhs = noOfLqhs; for(Uint32 i = 0; ilqhNodeId[i] = regTcPtr->tcNodedata[i]; } } /* ************************************************************> */ /* NO READ LENGTH SENT FROM TC. SEQUENTIAL NUMBER IS 1 AND IT */ /* IS SENT TO A PRIMARY NODE. */ /* ************************************************************> */ LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)signal->getDataPtrSend(); sig0 = tcConnectptr.i; sig2 = regCachePtr->hashValue; sig4 = cownref; sig5 = regTcPtr->savePointId; lqhKeyReq->clientConnectPtr = sig0; lqhKeyReq->attrLen = tslrAttrLen; lqhKeyReq->hashValue = sig2; lqhKeyReq->requestInfo = Tdata10; lqhKeyReq->tcBlockref = sig4; lqhKeyReq->savePointId = sig5; sig0 = regCachePtr->tableref + ((regCachePtr->schemaVersion << 16) & 0xFFFF0000); sig1 = regCachePtr->fragmentid + (regTcPtr->tcNodedata[1] << 16); sig2 = regApiPtr->transid[0]; sig3 = regApiPtr->transid[1]; sig4 = (regTcPtr->isIndexOp == 2) ? reference() : regApiPtr->ndbapiBlockref; sig5 = regTcPtr->clientData; sig6 = regCachePtr->scanInfo; if (! dirtyRead) { regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[0]); regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[1]); regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[2]); regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[3]); } lqhKeyReq->tableSchemaVersion = sig0; lqhKeyReq->fragmentData = sig1; lqhKeyReq->transId1 = sig2; lqhKeyReq->transId2 = sig3; lqhKeyReq->scanInfo = sig6; lqhKeyReq->variableData[0] = sig4; lqhKeyReq->variableData[1] = sig5; UintR nextPos = 2; if (regTcPtr->lastReplicaNo > 1) { sig0 = (UintR)regTcPtr->tcNodedata[2] + (UintR)(regTcPtr->tcNodedata[3] << 16); lqhKeyReq->variableData[nextPos] = sig0; nextPos++; }//if sig0 = regCachePtr->keydata[0]; sig1 = regCachePtr->keydata[1]; sig2 = regCachePtr->keydata[2]; sig3 = regCachePtr->keydata[3]; UintR Tkeylen = regCachePtr->keylen; lqhKeyReq->variableData[nextPos + 0] = sig0; lqhKeyReq->variableData[nextPos + 1] = sig1; lqhKeyReq->variableData[nextPos + 2] = sig2; lqhKeyReq->variableData[nextPos + 3] = sig3; if (Tkeylen < 4) { nextPos += Tkeylen; } else { nextPos += 4; }//if sig0 = regCachePtr->attrinfo0; sig1 = regCachePtr->attrinfo15[0]; sig2 = regCachePtr->attrinfo15[1]; sig3 = regCachePtr->attrinfo15[2]; sig4 = regCachePtr->attrinfo15[3]; UintR TlenAi = regCachePtr->lenAiInTckeyreq; lqhKeyReq->variableData[nextPos + 0] = sig0; lqhKeyReq->variableData[nextPos + 1] = sig1; lqhKeyReq->variableData[nextPos + 2] = sig2; lqhKeyReq->variableData[nextPos + 3] = sig3; lqhKeyReq->variableData[nextPos + 4] = sig4; nextPos += TlenAi; // Reset trigger count regTcPtr->accumulatingTriggerData.i = RNIL; regTcPtr->accumulatingTriggerData.p = NULL; regTcPtr->noFiredTriggers = 0; regTcPtr->triggerExecutionCount = 0; sendSignal(TBRef, GSN_LQHKEYREQ, signal, nextPos + LqhKeyReq::FixedSignalLength, JBB); }//Dbtc::sendlqhkeyreq() void Dbtc::packLqhkeyreq040Lab(Signal* signal, UintR anAttrBufIndex, BlockReference TBRef) { TcConnectRecord * const regTcPtr = tcConnectptr.p; #ifdef ERROR_INSERT ApiConnectRecord * const regApiPtr = apiConnectptr.p; if (ERROR_INSERTED(8009)) { if (regApiPtr->apiConnectstate == CS_STARTED) { attrbufptr.i = RNIL; CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8010)) { if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { attrbufptr.i = RNIL; CLEAR_ERROR_INSERT_VALUE; return; }//if }//if #endif UintR TattrbufFilesize = cattrbufFilesize; AttrbufRecord *localAttrbufRecord = attrbufRecord; while (1) { if (anAttrBufIndex == RNIL) { UintR TtcTimer = ctcTimer; UintR Tread = (regTcPtr->operation == ZREAD); UintR Tdirty = (regTcPtr->dirtyOp == ZTRUE); UintR Tboth = Tread & Tdirty; setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); jam(); /*-------------------------------------------------------------------- * WE HAVE SENT ALL THE SIGNALS OF THIS OPERATION. SET STATE AND EXIT. *---------------------------------------------------------------------*/ releaseAttrinfo(); if (Tboth) { jam(); releaseDirtyRead(signal, apiConnectptr, tcConnectptr.p); return; }//if regTcPtr->tcConnectstate = OS_OPERATING; return; }//if if (anAttrBufIndex < TattrbufFilesize) { AttrbufRecord * const regAttrPtr = &localAttrbufRecord[anAttrBufIndex]; anAttrBufIndex = regAttrPtr->attrbuf[ZINBUF_NEXT]; sendAttrinfo(signal, tcConnectptr.i, regAttrPtr, TBRef); } else { TCKEY_abort(signal, 17); return; }//if }//while }//Dbtc::packLqhkeyreq040Lab() /* ========================================================================= */ /* ------- RELEASE ALL ATTRINFO RECORDS IN AN OPERATION RECORD ------- */ /* ========================================================================= */ void Dbtc::releaseAttrinfo() { UintR Tmp; AttrbufRecordPtr Tattrbufptr; CacheRecord * const regCachePtr = cachePtr.p; UintR TattrbufFilesize = cattrbufFilesize; UintR TfirstfreeAttrbuf = cfirstfreeAttrbuf; Tattrbufptr.i = regCachePtr->firstAttrbuf; AttrbufRecord *localAttrbufRecord = attrbufRecord; while (Tattrbufptr.i < TattrbufFilesize) { Tattrbufptr.p = &localAttrbufRecord[Tattrbufptr.i]; Tmp = Tattrbufptr.p->attrbuf[ZINBUF_NEXT]; Tattrbufptr.p->attrbuf[ZINBUF_NEXT] = TfirstfreeAttrbuf; TfirstfreeAttrbuf = Tattrbufptr.i; Tattrbufptr.i = Tmp; jam(); }//while if (Tattrbufptr.i == RNIL) { //--------------------------------------------------- // Now we will release the cache record at the same // time as releasing the attrinfo records. //--------------------------------------------------- ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TfirstfreeCacheRec = cfirstfreeCacheRec; UintR TCacheIndex = cachePtr.i; cfirstfreeAttrbuf = TfirstfreeAttrbuf; regCachePtr->nextCacheRec = TfirstfreeCacheRec; cfirstfreeCacheRec = TCacheIndex; regApiPtr->cachePtr = RNIL; return; }//if systemErrorLab(0, __LINE__); return; }//Dbtc::releaseAttrinfo() /* ========================================================================= */ /* ------- RELEASE ALL RECORDS CONNECTED TO A DIRTY OPERATION ------- */ /* ========================================================================= */ void Dbtc::releaseDirtyRead(Signal* signal, ApiConnectRecordPtr regApiPtr, TcConnectRecord* regTcPtr) { Uint32 Ttckeyrec = regApiPtr.p->tckeyrec; Uint32 TclientData = regTcPtr->clientData; Uint32 Tnode = regTcPtr->tcNodedata[0]; Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; Uint32 TsimpleReadCount = c_counters.csimpleReadCount; ConnectionState state = regApiPtr.p->apiConnectstate; regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::DirtyReadBit | Tnode; regApiPtr.p->tckeyrec = Ttckeyrec + 2; unlinkReadyTcCon(signal); releaseTcCon(); /** * No LQHKEYCONF in Simple/Dirty read * Therefore decrese no LQHKEYCONF(REF) we are waiting for */ c_counters.csimpleReadCount = TsimpleReadCount + 1; regApiPtr.p->lqhkeyreqrec = --Tlqhkeyreqrec; if(Tlqhkeyreqrec == 0) { /** * Special case of lqhKeyConf_checkTransactionState: * - commit with zero operations: handle only for simple read */ sendtckeyconf(signal, state == CS_START_COMMITTING); regApiPtr.p->apiConnectstate = (state == CS_START_COMMITTING ? CS_CONNECTED : state); setApiConTimer(regApiPtr.i, 0, __LINE__); return; } /** * Emulate LQHKEYCONF */ lqhKeyConf_checkTransactionState(signal, regApiPtr); }//Dbtc::releaseDirtyRead() /* ------------------------------------------------------------------------- */ /* ------- CHECK IF ALL TC CONNECTIONS ARE COMPLETED ------- */ /* ------------------------------------------------------------------------- */ void Dbtc::unlinkReadyTcCon(Signal* signal) { TcConnectRecordPtr urtTcConnectptr; TcConnectRecord * const regTcPtr = tcConnectptr.p; TcConnectRecord *localTcConnectRecord = tcConnectRecord; UintR TtcConnectFilesize = ctcConnectFilesize; ApiConnectRecord * const regApiPtr = apiConnectptr.p; if (regTcPtr->prevTcConnect != RNIL) { jam(); urtTcConnectptr.i = regTcPtr->prevTcConnect; ptrCheckGuard(urtTcConnectptr, TtcConnectFilesize, localTcConnectRecord); urtTcConnectptr.p->nextTcConnect = regTcPtr->nextTcConnect; } else { jam(); regApiPtr->firstTcConnect = regTcPtr->nextTcConnect; }//if if (regTcPtr->nextTcConnect != RNIL) { jam(); urtTcConnectptr.i = regTcPtr->nextTcConnect; ptrCheckGuard(urtTcConnectptr, TtcConnectFilesize, localTcConnectRecord); urtTcConnectptr.p->prevTcConnect = regTcPtr->prevTcConnect; } else { jam(); regApiPtr->lastTcConnect = tcConnectptr.p->prevTcConnect; }//if }//Dbtc::unlinkReadyTcCon() void Dbtc::releaseTcCon() { TcConnectRecord * const regTcPtr = tcConnectptr.p; UintR TfirstfreeTcConnect = cfirstfreeTcConnect; UintR TconcurrentOp = c_counters.cconcurrentOp; UintR TtcConnectptrIndex = tcConnectptr.i; regTcPtr->tcConnectstate = OS_CONNECTED; regTcPtr->nextTcConnect = TfirstfreeTcConnect; regTcPtr->apiConnect = RNIL; regTcPtr->isIndexOp = false; regTcPtr->indexOp = RNIL; cfirstfreeTcConnect = TtcConnectptrIndex; c_counters.cconcurrentOp = TconcurrentOp - 1; }//Dbtc::releaseTcCon() void Dbtc::execPACKED_SIGNAL(Signal* signal) { LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); UintR Ti; UintR Tstep = 0; UintR Tlength; UintR TpackedData[28]; UintR Tdata1, Tdata2, Tdata3, Tdata4; jamEntry(); Tlength = signal->length(); if (Tlength > 25) { jam(); systemErrorLab(signal, __LINE__); return; }//if Uint32* TpackDataPtr; for (Ti = 0; Ti < Tlength; Ti += 4) { Uint32* TsigDataPtr = &signal->theData[Ti]; Tdata1 = TsigDataPtr[0]; Tdata2 = TsigDataPtr[1]; Tdata3 = TsigDataPtr[2]; Tdata4 = TsigDataPtr[3]; TpackDataPtr = &TpackedData[Ti]; TpackDataPtr[0] = Tdata1; TpackDataPtr[1] = Tdata2; TpackDataPtr[2] = Tdata3; TpackDataPtr[3] = Tdata4; }//for while (Tlength > Tstep) { TpackDataPtr = &TpackedData[Tstep]; Tdata1 = TpackDataPtr[0]; Tdata2 = TpackDataPtr[1]; Tdata3 = TpackDataPtr[2]; lqhKeyConf->connectPtr = Tdata1 & 0x0FFFFFFF; lqhKeyConf->opPtr = Tdata2; lqhKeyConf->userRef = Tdata3; switch (Tdata1 >> 28) { case ZCOMMITTED: signal->header.theLength = 3; execCOMMITTED(signal); Tstep += 3; break; case ZCOMPLETED: signal->header.theLength = 3; execCOMPLETED(signal); Tstep += 3; break; case ZLQHKEYCONF: jam(); Tdata1 = TpackDataPtr[3]; Tdata2 = TpackDataPtr[4]; Tdata3 = TpackDataPtr[5]; Tdata4 = TpackDataPtr[6]; lqhKeyConf->readLen = Tdata1; lqhKeyConf->transId1 = Tdata2; lqhKeyConf->transId2 = Tdata3; lqhKeyConf->noFiredTriggers = Tdata4; signal->header.theLength = LqhKeyConf::SignalLength; execLQHKEYCONF(signal); Tstep += LqhKeyConf::SignalLength; break; default: systemErrorLab(signal, __LINE__); return; }//switch }//while return; }//Dbtc::execPACKED_SIGNAL() void Dbtc::execLQHKEYCONF(Signal* signal) { const LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); UintR compare_transid1, compare_transid2; BlockReference tlastLqhBlockref; UintR tlastLqhConnect; UintR treadlenAi; UintR TtcConnectptrIndex; UintR TtcConnectFilesize = ctcConnectFilesize; tlastLqhConnect = lqhKeyConf->connectPtr; TtcConnectptrIndex = lqhKeyConf->opPtr; tlastLqhBlockref = lqhKeyConf->userRef; treadlenAi = lqhKeyConf->readLen; TcConnectRecord *localTcConnectRecord = tcConnectRecord; /*------------------------------------------------------------------------ * NUMBER OF EXTERNAL TRIGGERS FIRED IN DATA[6] * OPERATION IS NOW COMPLETED. CHECK FOR CORRECT OPERATION POINTER * TO ENSURE NO CRASHES BECAUSE OF ERRONEUS NODES. CHECK STATE OF * OPERATION. THEN SET OPERATION STATE AND RETRIEVE ALL POINTERS * OF THIS OPERATION. PUT COMPLETED OPERATION IN LIST OF COMPLETED * OPERATIONS ON THE LQH CONNECT RECORD. *------------------------------------------------------------------------ * THIS SIGNAL ALWAYS ARRIVE BEFORE THE ABORTED SIGNAL ARRIVES SINCE IT USES * THE SAME PATH BACK TO TC AS THE ABORTED SIGNAL DO. WE DO HOWEVER HAVE A * PROBLEM WHEN WE ENCOUNTER A TIME-OUT WAITING FOR THE ABORTED SIGNAL. * THEN THIS SIGNAL MIGHT ARRIVE WHEN THE TC CONNECT RECORD HAVE BEEN REUSED * BY OTHER TRANSACTION THUS WE CHECK THE TRANSACTION ID OF THE SIGNAL * BEFORE ACCEPTING THIS SIGNAL. * Due to packing of LQHKEYCONF the ABORTED signal can now arrive before * this. * This is more reason to ignore the signal if not all states are correct. *------------------------------------------------------------------------*/ if (TtcConnectptrIndex >= TtcConnectFilesize) { TCKEY_abort(signal, 25); return; }//if TcConnectRecord* const regTcPtr = &localTcConnectRecord[TtcConnectptrIndex]; OperationState TtcConnectstate = regTcPtr->tcConnectstate; tcConnectptr.i = TtcConnectptrIndex; tcConnectptr.p = regTcPtr; if (TtcConnectstate != OS_OPERATING) { warningReport(signal, 23); return; }//if ApiConnectRecord *localApiConnectRecord = apiConnectRecord; UintR TapiConnectptrIndex = regTcPtr->apiConnect; UintR TapiConnectFilesize = capiConnectFilesize; UintR Ttrans1 = lqhKeyConf->transId1; UintR Ttrans2 = lqhKeyConf->transId2; Uint32 noFired = lqhKeyConf->noFiredTriggers; if (TapiConnectptrIndex >= TapiConnectFilesize) { TCKEY_abort(signal, 29); return; }//if Ptr regApiPtr; regApiPtr.i = TapiConnectptrIndex; regApiPtr.p = &localApiConnectRecord[TapiConnectptrIndex]; apiConnectptr.i = TapiConnectptrIndex; apiConnectptr.p = regApiPtr.p; compare_transid1 = regApiPtr.p->transid[0] ^ Ttrans1; compare_transid2 = regApiPtr.p->transid[1] ^ Ttrans2; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 24); return; }//if #ifdef ERROR_INSERT if (ERROR_INSERTED(8029)) { systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8003)) { if (regApiPtr.p->apiConnectstate == CS_STARTED) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8004)) { if (regApiPtr.p->apiConnectstate == CS_RECEIVING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8005)) { if (regApiPtr.p->apiConnectstate == CS_REC_COMMITTING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8006)) { if (regApiPtr.p->apiConnectstate == CS_START_COMMITTING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8023)) { SET_ERROR_INSERT_VALUE(8024); return; }//if #endif UintR TtcTimer = ctcTimer; regTcPtr->lastLqhCon = tlastLqhConnect; regTcPtr->lastLqhNodeId = refToNode(tlastLqhBlockref); regTcPtr->noFiredTriggers = noFired; UintR Ttckeyrec = (UintR)regApiPtr.p->tckeyrec; UintR TclientData = regTcPtr->clientData; UintR TdirtyOp = regTcPtr->dirtyOp; Uint32 TopSimple = regTcPtr->opSimple; Uint32 Toperation = regTcPtr->operation; ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate; if (Ttckeyrec > (ZTCOPCONF_SIZE - 2)) { TCKEY_abort(signal, 30); return; } if (TapiConnectstate == CS_ABORTING) { warningReport(signal, 27); return; }//if setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); if (regTcPtr->isIndexOp) { jam(); // This was an internal TCKEYREQ // will be returned unpacked regTcPtr->attrInfoLen = treadlenAi; } else { if (noFired == 0 && regTcPtr->triggeringOperation == RNIL) { jam(); /* * Skip counting triggering operations the first round * since they will enter execLQHKEYCONF a second time * Skip counting internally generated TcKeyReq */ regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; regApiPtr.p->tcSendArray[Ttckeyrec + 1] = treadlenAi; regApiPtr.p->tckeyrec = Ttckeyrec + 2; }//if }//if if (TdirtyOp == ZTRUE) { UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; jam(); releaseDirtyWrite(signal); regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1; } else if (Toperation == ZREAD && TopSimple) { UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; jam(); unlinkReadyTcCon(signal); releaseTcCon(); regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1; } else { jam(); if (noFired == 0) { jam(); // No triggers to execute UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec; regApiPtr.p->lqhkeyconfrec = Tlqhkeyconfrec + 1; regTcPtr->tcConnectstate = OS_PREPARED; } }//if /** * And now decide what to do next */ if (regTcPtr->triggeringOperation != RNIL) { jam(); // This operation was created by a trigger execting operation // Restart it if we have executed all it's triggers TcConnectRecordPtr opPtr; opPtr.i = regTcPtr->triggeringOperation; ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord); opPtr.p->triggerExecutionCount--; if (opPtr.p->triggerExecutionCount == 0) { /* We have completed current trigger execution Continue triggering operation */ jam(); continueTriggeringOp(signal, opPtr.p); } } else if (noFired == 0) { // This operation did not fire any triggers, finish operation jam(); if (regTcPtr->isIndexOp) { jam(); setupIndexOpReturn(regApiPtr.p, regTcPtr); } lqhKeyConf_checkTransactionState(signal, regApiPtr); } else { // We have fired triggers jam(); saveTriggeringOpState(signal, regTcPtr); if (regTcPtr->noReceivedTriggers == noFired) { // We have received all data jam(); executeTriggers(signal, ®ApiPtr); } // else wait for more trigger data } }//Dbtc::execLQHKEYCONF() void Dbtc::setupIndexOpReturn(ApiConnectRecord* regApiPtr, TcConnectRecord* regTcPtr) { regApiPtr->indexOpReturn = true; regApiPtr->indexOp = regTcPtr->indexOp; regApiPtr->clientData = regTcPtr->clientData; regApiPtr->attrInfoLen = regTcPtr->attrInfoLen; } /** * lqhKeyConf_checkTransactionState * * This functions checks state variables, and * decides if it should wait for more LQHKEYCONF signals * or if it should start commiting */ void Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, Ptr regApiPtr) { /*---------------------------------------------------------------*/ /* IF THE COMMIT FLAG IS SET IN SIGNAL TCKEYREQ THEN DBTC HAS TO */ /* SEND TCKEYCONF FOR ALL OPERATIONS EXCEPT THE LAST ONE. WHEN */ /* THE TRANSACTION THEN IS COMMITTED TCKEYCONF IS SENT FOR THE */ /* WHOLE TRANSACTION */ /* IF THE COMMIT FLAG IS NOT RECECIVED DBTC WILL SEND TCKEYCONF */ /* FOR ALL OPERATIONS, AND THEN WAIT FOR THE API TO CONCLUDE THE */ /* TRANSACTION */ /*---------------------------------------------------------------*/ ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate; UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec; UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; int TnoOfOutStanding = Tlqhkeyreqrec - Tlqhkeyconfrec; switch (TapiConnectstate) { case CS_START_COMMITTING: if (TnoOfOutStanding == 0) { jam(); diverify010Lab(signal); return; } else if (TnoOfOutStanding > 0) { if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; }//if jam(); return; } else { TCKEY_abort(signal, 44); return; }//if return; case CS_STARTED: case CS_RECEIVING: if (TnoOfOutStanding == 0) { jam(); sendtckeyconf(signal, 2); return; } else { if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; }//if jam(); }//if return; case CS_REC_COMMITTING: if (TnoOfOutStanding > 0) { if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; }//if jam(); return; }//if TCKEY_abort(signal, 45); return; case CS_CONNECTED: jam(); /*---------------------------------------------------------------*/ /* WE HAVE CONCLUDED THE TRANSACTION SINCE IT WAS ONLY */ /* CONSISTING OF DIRTY WRITES AND ALL OF THOSE WERE */ /* COMPLETED. ENSURE TCKEYREC IS ZERO TO PREVENT ERRORS. */ /*---------------------------------------------------------------*/ regApiPtr.p->tckeyrec = 0; return; default: TCKEY_abort(signal, 46); return; }//switch }//Dbtc::lqhKeyConf_checkTransactionState() void Dbtc::sendtckeyconf(Signal* signal, UintR TcommitFlag) { if(ERROR_INSERTED(8049)){ CLEAR_ERROR_INSERT_VALUE; signal->theData[0] = TcContinueB::DelayTCKEYCONF; signal->theData[1] = apiConnectptr.i; signal->theData[2] = TcommitFlag; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 3000, 3); return; } HostRecordPtr localHostptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; const UintR TopWords = (UintR)regApiPtr->tckeyrec; localHostptr.i = refToNode(regApiPtr->ndbapiBlockref); const Uint32 type = getNodeInfo(localHostptr.i).m_type; const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::MGM); const BlockNumber TblockNum = refToBlock(regApiPtr->ndbapiBlockref); const Uint32 Tmarker = (regApiPtr->commitAckMarker == RNIL) ? 0 : 1; ptrAss(localHostptr, hostRecord); UintR TcurrLen = localHostptr.p->noOfWordsTCKEYCONF; UintR confInfo = 0; TcKeyConf::setCommitFlag(confInfo, TcommitFlag == 1); TcKeyConf::setMarkerFlag(confInfo, Tmarker); const UintR TpacketLen = 6 + TopWords; regApiPtr->tckeyrec = 0; if (regApiPtr->indexOpReturn) { jam(); // Return internally generated TCKEY TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtrSend(); TcKeyConf::setNoOfOperations(confInfo, 1); tcKeyConf->apiConnectPtr = regApiPtr->indexOp; tcKeyConf->gci = regApiPtr->globalcheckpointid; tcKeyConf->confInfo = confInfo; tcKeyConf->transId1 = regApiPtr->transid[0]; tcKeyConf->transId2 = regApiPtr->transid[1]; tcKeyConf->operations[0].apiOperationPtr = regApiPtr->clientData; tcKeyConf->operations[0].attrInfoLen = regApiPtr->attrInfoLen; Uint32 sigLen = TcKeyConf::StaticLength + TcKeyConf::OperationLength; EXECUTE_DIRECT(DBTC, GSN_TCKEYCONF, signal, sigLen); regApiPtr->indexOpReturn = false; if (TopWords == 0) { jam(); return; // No queued TcKeyConf }//if }//if if(TcommitFlag){ jam(); regApiPtr->m_exec_flag = 0; } TcKeyConf::setNoOfOperations(confInfo, (TopWords >> 1)); if ((TpacketLen > 25) || !is_api){ TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtrSend(); jam(); tcKeyConf->apiConnectPtr = regApiPtr->ndbapiConnect; tcKeyConf->gci = regApiPtr->globalcheckpointid;; tcKeyConf->confInfo = confInfo; tcKeyConf->transId1 = regApiPtr->transid[0]; tcKeyConf->transId2 = regApiPtr->transid[1]; copyFromToLen(®ApiPtr->tcSendArray[0], (UintR*)&tcKeyConf->operations, (UintR)ZTCOPCONF_SIZE); sendSignal(regApiPtr->ndbapiBlockref, GSN_TCKEYCONF, signal, (TpacketLen - 1), JBB); return; } else if (((TcurrLen + TpacketLen) > 25) && (TcurrLen > 0)) { jam(); sendPackedTCKEYCONF(signal, localHostptr.p, localHostptr.i); TcurrLen = 0; } else { jam(); updatePackedList(signal, localHostptr.p, localHostptr.i); }//if // ------------------------------------------------------------------------- // The header contains the block reference of receiver plus the real signal // length - 3, since we have the real signal length plus one additional word // for the header we have to do - 4. // ------------------------------------------------------------------------- UintR Tpack0 = (TblockNum << 16) + (TpacketLen - 4); UintR Tpack1 = regApiPtr->ndbapiConnect; UintR Tpack2 = regApiPtr->globalcheckpointid; UintR Tpack3 = confInfo; UintR Tpack4 = regApiPtr->transid[0]; UintR Tpack5 = regApiPtr->transid[1]; localHostptr.p->noOfWordsTCKEYCONF = TcurrLen + TpacketLen; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 0] = Tpack0; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 1] = Tpack1; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 2] = Tpack2; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 3] = Tpack3; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 4] = Tpack4; localHostptr.p->packedWordsTCKEYCONF[TcurrLen + 5] = Tpack5; UintR Ti; for (Ti = 6; Ti < TpacketLen; Ti++) { localHostptr.p->packedWordsTCKEYCONF[TcurrLen + Ti] = regApiPtr->tcSendArray[Ti - 6]; }//for }//Dbtc::sendtckeyconf() void Dbtc::copyFromToLen(UintR* sourceBuffer, UintR* destBuffer, UintR Tlen) { UintR Tindex = 0; UintR Ti; while (Tlen >= 4) { UintR Tdata0 = sourceBuffer[Tindex + 0]; UintR Tdata1 = sourceBuffer[Tindex + 1]; UintR Tdata2 = sourceBuffer[Tindex + 2]; UintR Tdata3 = sourceBuffer[Tindex + 3]; Tlen -= 4; destBuffer[Tindex + 0] = Tdata0; destBuffer[Tindex + 1] = Tdata1; destBuffer[Tindex + 2] = Tdata2; destBuffer[Tindex + 3] = Tdata3; Tindex += 4; }//while for (Ti = 0; Ti < Tlen; Ti++, Tindex++) { destBuffer[Tindex] = sourceBuffer[Tindex]; }//for }//Dbtc::copyFromToLen() void Dbtc::execSEND_PACKED(Signal* signal) { HostRecordPtr Thostptr; HostRecord *localHostRecord = hostRecord; UintR i; UintR TpackedListIndex = cpackedListIndex; jamEntry(); for (i = 0; i < TpackedListIndex; i++) { Thostptr.i = cpackedList[i]; ptrAss(Thostptr, localHostRecord); arrGuard(Thostptr.i - 1, MAX_NODES - 1); UintR TnoOfPackedWordsLqh = Thostptr.p->noOfPackedWordsLqh; UintR TnoOfWordsTCKEYCONF = Thostptr.p->noOfWordsTCKEYCONF; UintR TnoOfWordsTCINDXCONF = Thostptr.p->noOfWordsTCINDXCONF; jam(); if (TnoOfPackedWordsLqh > 0) { jam(); sendPackedSignalLqh(signal, Thostptr.p); }//if if (TnoOfWordsTCKEYCONF > 0) { jam(); sendPackedTCKEYCONF(signal, Thostptr.p, (Uint32)Thostptr.i); }//if if (TnoOfWordsTCINDXCONF > 0) { jam(); sendPackedTCINDXCONF(signal, Thostptr.p, (Uint32)Thostptr.i); }//if Thostptr.p->inPackedList = false; }//for cpackedListIndex = 0; return; }//Dbtc::execSEND_PACKED() void Dbtc::updatePackedList(Signal* signal, HostRecord* ahostptr, Uint16 ahostIndex) { if (ahostptr->inPackedList == false) { UintR TpackedListIndex = cpackedListIndex; jam(); ahostptr->inPackedList = true; cpackedList[TpackedListIndex] = ahostIndex; cpackedListIndex = TpackedListIndex + 1; }//if }//Dbtc::updatePackedList() void Dbtc::sendPackedSignalLqh(Signal* signal, HostRecord * ahostptr) { UintR Tj; UintR TnoOfWords = ahostptr->noOfPackedWordsLqh; for (Tj = 0; Tj < TnoOfWords; Tj += 4) { UintR sig0 = ahostptr->packedWordsLqh[Tj + 0]; UintR sig1 = ahostptr->packedWordsLqh[Tj + 1]; UintR sig2 = ahostptr->packedWordsLqh[Tj + 2]; UintR sig3 = ahostptr->packedWordsLqh[Tj + 3]; signal->theData[Tj + 0] = sig0; signal->theData[Tj + 1] = sig1; signal->theData[Tj + 2] = sig2; signal->theData[Tj + 3] = sig3; }//for ahostptr->noOfPackedWordsLqh = 0; sendSignal(ahostptr->hostLqhBlockRef, GSN_PACKED_SIGNAL, signal, TnoOfWords, JBB); }//Dbtc::sendPackedSignalLqh() void Dbtc::sendPackedTCKEYCONF(Signal* signal, HostRecord * ahostptr, UintR hostId) { UintR Tj; UintR TnoOfWords = ahostptr->noOfWordsTCKEYCONF; BlockReference TBref = numberToRef(API_PACKED, hostId); for (Tj = 0; Tj < ahostptr->noOfWordsTCKEYCONF; Tj += 4) { UintR sig0 = ahostptr->packedWordsTCKEYCONF[Tj + 0]; UintR sig1 = ahostptr->packedWordsTCKEYCONF[Tj + 1]; UintR sig2 = ahostptr->packedWordsTCKEYCONF[Tj + 2]; UintR sig3 = ahostptr->packedWordsTCKEYCONF[Tj + 3]; signal->theData[Tj + 0] = sig0; signal->theData[Tj + 1] = sig1; signal->theData[Tj + 2] = sig2; signal->theData[Tj + 3] = sig3; }//for ahostptr->noOfWordsTCKEYCONF = 0; sendSignal(TBref, GSN_TCKEYCONF, signal, TnoOfWords, JBB); }//Dbtc::sendPackedTCKEYCONF() void Dbtc::sendPackedTCINDXCONF(Signal* signal, HostRecord * ahostptr, UintR hostId) { UintR Tj; UintR TnoOfWords = ahostptr->noOfWordsTCINDXCONF; BlockReference TBref = numberToRef(API_PACKED, hostId); for (Tj = 0; Tj < ahostptr->noOfWordsTCINDXCONF; Tj += 4) { UintR sig0 = ahostptr->packedWordsTCINDXCONF[Tj + 0]; UintR sig1 = ahostptr->packedWordsTCINDXCONF[Tj + 1]; UintR sig2 = ahostptr->packedWordsTCINDXCONF[Tj + 2]; UintR sig3 = ahostptr->packedWordsTCINDXCONF[Tj + 3]; signal->theData[Tj + 0] = sig0; signal->theData[Tj + 1] = sig1; signal->theData[Tj + 2] = sig2; signal->theData[Tj + 3] = sig3; }//for ahostptr->noOfWordsTCINDXCONF = 0; sendSignal(TBref, GSN_TCINDXCONF, signal, TnoOfWords, JBB); }//Dbtc::sendPackedTCINDXCONF() /* 4.3.11 DIVERIFY --------------- */ /*****************************************************************************/ /* D I V E R I F Y */ /* */ /*****************************************************************************/ void Dbtc::diverify010Lab(Signal* signal) { UintR TfirstfreeApiConnectCopy = cfirstfreeApiConnectCopy; ApiConnectRecord * const regApiPtr = apiConnectptr.p; signal->theData[0] = apiConnectptr.i; if (ERROR_INSERTED(8022)) { jam(); systemErrorLab(signal, __LINE__); }//if if (regApiPtr->lqhkeyreqrec) { if (TfirstfreeApiConnectCopy != RNIL) { seizeApiConnectCopy(signal); regApiPtr->apiConnectstate = CS_PREPARE_TO_COMMIT; /*----------------------------------------------------------------------- * WE COME HERE ONLY IF THE TRANSACTION IS PREPARED ON ALL TC CONNECTIONS * THUS WE CAN START THE COMMIT PHASE BY SENDING DIVERIFY ON ALL TC * CONNECTIONS AND THEN WHEN ALL DIVERIFYCONF HAVE BEEN RECEIVED THE * COMMIT MESSAGE CAN BE SENT TO ALL INVOLVED PARTS. *---------------------------------------------------------------------*/ EXECUTE_DIRECT(DBDIH, GSN_DIVERIFYREQ, signal, 1); if (signal->theData[2] == 0) { execDIVERIFYCONF(signal); } return; } else { /*----------------------------------------------------------------------- * There were no free copy connections available. We must abort the * transaction since otherwise we will have a problem with the report * to the application. * This should more or less not happen but if it happens we do * not want to crash and we do not want to create code to handle it * properly since it is difficult to test it and will be complex to * handle a problem more or less not occurring. *---------------------------------------------------------------------*/ terrorCode = ZSEIZE_API_COPY_ERROR; abortErrorLab(signal); return; } } else { jam(); sendtckeyconf(signal, 1); regApiPtr->apiConnectstate = CS_CONNECTED; regApiPtr->m_transaction_nodes.clear(); setApiConTimer(apiConnectptr.i, 0,__LINE__); } }//Dbtc::diverify010Lab() /* ------------------------------------------------------------------------- */ /* ------- SEIZE_API_CONNECT ------- */ /* SEIZE CONNECT RECORD FOR A REQUEST */ /* ------------------------------------------------------------------------- */ void Dbtc::seizeApiConnectCopy(Signal* signal) { ApiConnectRecordPtr locApiConnectptr; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; UintR TapiConnectFilesize = capiConnectFilesize; ApiConnectRecord * const regApiPtr = apiConnectptr.p; locApiConnectptr.i = cfirstfreeApiConnectCopy; ptrCheckGuard(locApiConnectptr, TapiConnectFilesize, localApiConnectRecord); cfirstfreeApiConnectCopy = locApiConnectptr.p->nextApiConnect; locApiConnectptr.p->nextApiConnect = RNIL; regApiPtr->apiCopyRecord = locApiConnectptr.i; regApiPtr->triggerPending = false; regApiPtr->isIndexOp = false; }//Dbtc::seizeApiConnectCopy() void Dbtc::execDIVERIFYCONF(Signal* signal) { UintR TapiConnectptrIndex = signal->theData[0]; UintR TapiConnectFilesize = capiConnectFilesize; UintR Tgci = signal->theData[1]; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; jamEntry(); if (ERROR_INSERTED(8017)) { CLEAR_ERROR_INSERT_VALUE; return; }//if if (TapiConnectptrIndex >= TapiConnectFilesize) { TCKEY_abort(signal, 31); return; }//if ApiConnectRecord * const regApiPtr = &localApiConnectRecord[TapiConnectptrIndex]; ConnectionState TapiConnectstate = regApiPtr->apiConnectstate; UintR TApifailureNr = regApiPtr->failureNr; UintR Tfailure_nr = cfailure_nr; apiConnectptr.i = TapiConnectptrIndex; apiConnectptr.p = regApiPtr; if (TapiConnectstate != CS_PREPARE_TO_COMMIT) { TCKEY_abort(signal, 32); return; }//if /*-------------------------------------------------------------------------- * THIS IS THE COMMIT POINT. IF WE ARRIVE HERE THE TRANSACTION IS COMMITTED * UNLESS EVERYTHING CRASHES BEFORE WE HAVE BEEN ABLE TO REPORT THE COMMIT * DECISION. THERE IS NO TURNING BACK FROM THIS DECISION FROM HERE ON. * WE WILL INSERT THE TRANSACTION INTO ITS PROPER QUEUE OF * TRANSACTIONS FOR ITS GLOBAL CHECKPOINT. *-------------------------------------------------------------------------*/ if (TApifailureNr != Tfailure_nr) { DIVER_node_fail_handling(signal, Tgci); return; }//if commitGciHandling(signal, Tgci); /************************************************************************** * C O M M I T * THE TRANSACTION HAVE NOW BEEN VERIFIED AND NOW THE COMMIT PHASE CAN START **************************************************************************/ UintR TtcConnectptrIndex = regApiPtr->firstTcConnect; UintR TtcConnectFilesize = ctcConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; regApiPtr->counter = regApiPtr->lqhkeyconfrec; regApiPtr->apiConnectstate = CS_COMMITTING; if (TtcConnectptrIndex >= TtcConnectFilesize) { TCKEY_abort(signal, 33); return; }//if TcConnectRecord* const regTcPtr = &localTcConnectRecord[TtcConnectptrIndex]; tcConnectptr.i = TtcConnectptrIndex; tcConnectptr.p = regTcPtr; commit020Lab(signal); }//Dbtc::execDIVERIFYCONF() /*--------------------------------------------------------------------------*/ /* COMMIT_GCI_HANDLING */ /* SET UP GLOBAL CHECKPOINT DATA STRUCTURE AT THE COMMIT POINT. */ /*--------------------------------------------------------------------------*/ void Dbtc::commitGciHandling(Signal* signal, UintR Tgci) { GcpRecordPtr localGcpPointer; UintR TgcpFilesize = cgcpFilesize; UintR Tfirstgcp = cfirstgcp; ApiConnectRecord * const regApiPtr = apiConnectptr.p; GcpRecord *localGcpRecord = gcpRecord; regApiPtr->globalcheckpointid = Tgci; if (Tfirstgcp != RNIL) { /* IF THIS GLOBAL CHECKPOINT ALREADY EXISTS */ localGcpPointer.i = Tfirstgcp; ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord); do { if (regApiPtr->globalcheckpointid == localGcpPointer.p->gcpId) { jam(); gcpPtr.i = localGcpPointer.i; gcpPtr.p = localGcpPointer.p; linkApiToGcp(signal); return; } else { localGcpPointer.i = localGcpPointer.p->nextGcp; jam(); if (localGcpPointer.i != RNIL) { jam(); ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord); continue; }//if }//if seizeGcp(signal); linkApiToGcp(signal); return; } while (1); } else { jam(); seizeGcp(signal); linkApiToGcp(signal); }//if }//Dbtc::commitGciHandling() /* --------------------------------------------------------------------------*/ /* -LINK AN API CONNECT RECORD IN STATE PREPARED INTO THE LIST WITH GLOBAL - */ /* CHECKPOINTS. WHEN THE TRANSACTION I COMPLETED THE API CONNECT RECORD IS */ /* LINKED OUT OF THE LIST. */ /*---------------------------------------------------------------------------*/ void Dbtc::linkApiToGcp(Signal* signal) { ApiConnectRecordPtr localApiConnectptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; GcpRecord * const regGcpPtr = gcpPtr.p; UintR TapiConnectptrIndex = apiConnectptr.i; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; regApiPtr->nextGcpConnect = RNIL; if (regGcpPtr->firstApiConnect == RNIL) { regGcpPtr->firstApiConnect = TapiConnectptrIndex; jam(); } else { UintR TapiConnectFilesize = capiConnectFilesize; localApiConnectptr.i = regGcpPtr->lastApiConnect; jam(); ptrCheckGuard(localApiConnectptr, TapiConnectFilesize, localApiConnectRecord); localApiConnectptr.p->nextGcpConnect = TapiConnectptrIndex; }//if UintR TlastApiConnect = regGcpPtr->lastApiConnect; regApiPtr->gcpPointer = gcpPtr.i; regApiPtr->prevGcpConnect = TlastApiConnect; regGcpPtr->lastApiConnect = TapiConnectptrIndex; }//Dbtc::linkApiToGcp() void Dbtc::seizeGcp(Signal* signal) { GcpRecordPtr tmpGcpPointer; GcpRecordPtr localGcpPointer; UintR Tfirstgcp = cfirstgcp; UintR Tglobalcheckpointid = apiConnectptr.p->globalcheckpointid; UintR TgcpFilesize = cgcpFilesize; GcpRecord *localGcpRecord = gcpRecord; localGcpPointer.i = cfirstfreeGcp; ptrCheckGuard(localGcpPointer, TgcpFilesize, localGcpRecord); UintR TfirstfreeGcp = localGcpPointer.p->nextGcp; localGcpPointer.p->gcpId = Tglobalcheckpointid; localGcpPointer.p->nextGcp = RNIL; localGcpPointer.p->firstApiConnect = RNIL; localGcpPointer.p->lastApiConnect = RNIL; localGcpPointer.p->gcpNomoretransRec = ZFALSE; cfirstfreeGcp = TfirstfreeGcp; if (Tfirstgcp == RNIL) { jam(); cfirstgcp = localGcpPointer.i; } else { tmpGcpPointer.i = clastgcp; jam(); ptrCheckGuard(tmpGcpPointer, TgcpFilesize, localGcpRecord); tmpGcpPointer.p->nextGcp = localGcpPointer.i; }//if clastgcp = localGcpPointer.i; gcpPtr = localGcpPointer; }//Dbtc::seizeGcp() /*---------------------------------------------------------------------------*/ // Send COMMIT messages to all LQH operations involved in the transaction. /*---------------------------------------------------------------------------*/ void Dbtc::commit020Lab(Signal* signal) { TcConnectRecordPtr localTcConnectptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TtcConnectFilesize = ctcConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; localTcConnectptr.p = tcConnectptr.p; setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); UintR Tcount = 0; do { /*----------------------------------------------------------------------- * WE ARE NOW READY TO RELEASE ALL OPERATIONS ON THE LQH *-----------------------------------------------------------------------*/ /* *********< */ /* COMMIT < */ /* *********< */ localTcConnectptr.i = localTcConnectptr.p->nextTcConnect; localTcConnectptr.p->tcConnectstate = OS_COMMITTING; sendCommitLqh(signal, localTcConnectptr.p); if (localTcConnectptr.i != RNIL) { Tcount = Tcount + 1; if (Tcount < 16 && !ERROR_INSERTED(8057)) { ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); jam(); continue; } else { jam(); if (ERROR_INSERTED(8014)) { CLEAR_ERROR_INSERT_VALUE; return; }//if signal->theData[0] = TcContinueB::ZSEND_COMMIT_LOOP; signal->theData[1] = apiConnectptr.i; signal->theData[2] = localTcConnectptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); return; }//if } else { jam(); if (ERROR_INSERTED(8057)) CLEAR_ERROR_INSERT_VALUE; regApiPtr->apiConnectstate = CS_COMMIT_SENT; return; }//if } while (1); }//Dbtc::commit020Lab() void Dbtc::sendCommitLqh(Signal* signal, TcConnectRecord * const regTcPtr) { HostRecordPtr Thostptr; UintR ThostFilesize = chostFilesize; ApiConnectRecord * const regApiPtr = apiConnectptr.p; Thostptr.i = regTcPtr->lastLqhNodeId; ptrCheckGuard(Thostptr, ThostFilesize, hostRecord); if (Thostptr.p->noOfPackedWordsLqh > 21) { jam(); sendPackedSignalLqh(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if UintR Tindex = Thostptr.p->noOfPackedWordsLqh; UintR* TDataPtr = &Thostptr.p->packedWordsLqh[Tindex]; UintR Tdata1 = regTcPtr->lastLqhCon; UintR Tdata2 = regApiPtr->globalcheckpointid; UintR Tdata3 = regApiPtr->transid[0]; UintR Tdata4 = regApiPtr->transid[1]; TDataPtr[0] = Tdata1 | (ZCOMMIT << 28); TDataPtr[1] = Tdata2; TDataPtr[2] = Tdata3; TDataPtr[3] = Tdata4; Thostptr.p->noOfPackedWordsLqh = Tindex + 4; }//Dbtc::sendCommitLqh() void Dbtc::DIVER_node_fail_handling(Signal* signal, UintR Tgci) { /*------------------------------------------------------------------------ * AT LEAST ONE NODE HAS FAILED DURING THE TRANSACTION. WE NEED TO CHECK IF * THIS IS SO SERIOUS THAT WE NEED TO ABORT THE TRANSACTION. IN BOTH THE * ABORT AND THE COMMIT CASES WE NEED TO SET-UP THE DATA FOR THE * ABORT/COMMIT/COMPLETE HANDLING AS ALSO USED BY TAKE OVER FUNCTIONALITY. *------------------------------------------------------------------------*/ tabortInd = ZFALSE; setupFailData(signal); if (false && tabortInd == ZFALSE) { jam(); commitGciHandling(signal, Tgci); toCommitHandlingLab(signal); } else { jam(); apiConnectptr.p->returnsignal = RS_TCROLLBACKREP; apiConnectptr.p->returncode = ZNODEFAIL_BEFORE_COMMIT; toAbortHandlingLab(signal); }//if return; }//Dbtc::DIVER_node_fail_handling() /* ------------------------------------------------------------------------- */ /* ------- ENTER COMMITTED ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dbtc::execCOMMITTED(Signal* signal) { TcConnectRecordPtr localTcConnectptr; ApiConnectRecordPtr localApiConnectptr; UintR TtcConnectFilesize = ctcConnectFilesize; UintR TapiConnectFilesize = capiConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; #ifdef ERROR_INSERT if (ERROR_INSERTED(8018)) { CLEAR_ERROR_INSERT_VALUE; return; }//if if (ERROR_INSERTED(8030)) { systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8025)) { SET_ERROR_INSERT_VALUE(8026); return; }//if if (ERROR_INSERTED(8041)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMMITTED, signal, 2000, 3); return; }//if if (ERROR_INSERTED(8042)) { SET_ERROR_INSERT_VALUE(8046); sendSignalWithDelay(cownref, GSN_COMMITTED, signal, 2000, 4); return; }//if #endif localTcConnectptr.i = signal->theData[0]; jamEntry(); ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); localApiConnectptr.i = localTcConnectptr.p->apiConnect; if (localTcConnectptr.p->tcConnectstate != OS_COMMITTING) { warningReport(signal, 4); return; }//if ptrCheckGuard(localApiConnectptr, TapiConnectFilesize, localApiConnectRecord); UintR Tcounter = localApiConnectptr.p->counter - 1; ConnectionState TapiConnectstate = localApiConnectptr.p->apiConnectstate; UintR Tdata1 = localApiConnectptr.p->transid[0] - signal->theData[1]; UintR Tdata2 = localApiConnectptr.p->transid[1] - signal->theData[2]; Tdata1 = Tdata1 | Tdata2; bool TcheckCondition = (TapiConnectstate != CS_COMMIT_SENT) || (Tcounter != 0); setApiConTimer(localApiConnectptr.i, ctcTimer, __LINE__); localApiConnectptr.p->counter = Tcounter; localTcConnectptr.p->tcConnectstate = OS_COMMITTED; if (Tdata1 != 0) { warningReport(signal, 5); return; }//if if (TcheckCondition) { jam(); /*-------------------------------------------------------*/ // We have not sent all COMMIT requests yet. We could be // in the state that all sent are COMMITTED but we are // still waiting for a CONTINUEB to send the rest of the // COMMIT requests. /*-------------------------------------------------------*/ return; }//if if (ERROR_INSERTED(8020)) { jam(); systemErrorLab(signal, __LINE__); }//if /*-------------------------------------------------------*/ /* THE ENTIRE TRANSACTION IS NOW COMMITED */ /* NOW WE NEED TO SEND THE RESPONSE TO THE APPLICATION. */ /* THE APPLICATION CAN THEN REUSE THE API CONNECTION AND */ /* THEREFORE WE NEED TO MOVE THE API CONNECTION TO A */ /* NEW API CONNECT RECORD. */ /*-------------------------------------------------------*/ apiConnectptr = localApiConnectptr; sendApiCommit(signal); ApiConnectRecord * const regApiPtr = apiConnectptr.p; localTcConnectptr.i = regApiPtr->firstTcConnect; UintR Tlqhkeyconfrec = regApiPtr->lqhkeyconfrec; ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); regApiPtr->counter = Tlqhkeyconfrec; tcConnectptr = localTcConnectptr; complete010Lab(signal); return; }//Dbtc::execCOMMITTED() /*-------------------------------------------------------*/ /* SEND_API_COMMIT */ /* SEND COMMIT DECISION TO THE API. */ /*-------------------------------------------------------*/ void Dbtc::sendApiCommit(Signal* signal) { ApiConnectRecord * const regApiPtr = apiConnectptr.p; if (regApiPtr->returnsignal == RS_TCKEYCONF) { sendtckeyconf(signal, 1); } else if (regApiPtr->returnsignal == RS_TC_COMMITCONF) { jam(); TcCommitConf * const commitConf = (TcCommitConf *)&signal->theData[0]; if(regApiPtr->commitAckMarker == RNIL){ jam(); commitConf->apiConnectPtr = regApiPtr->ndbapiConnect; } else { jam(); commitConf->apiConnectPtr = regApiPtr->ndbapiConnect | 1; } commitConf->transId1 = regApiPtr->transid[0]; commitConf->transId2 = regApiPtr->transid[1]; commitConf->gci = regApiPtr->globalcheckpointid; sendSignal(regApiPtr->ndbapiBlockref, GSN_TC_COMMITCONF, signal, TcCommitConf::SignalLength, JBB); } else if (regApiPtr->returnsignal == RS_NO_RETURN) { jam(); } else { TCKEY_abort(signal, 37); return; }//if UintR TapiConnectFilesize = capiConnectFilesize; UintR TcommitCount = c_counters.ccommitCount; UintR TapiIndex = apiConnectptr.i; UintR TnewApiIndex = regApiPtr->apiCopyRecord; UintR TapiFailState = regApiPtr->apiFailState; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; tmpApiConnectptr.p = apiConnectptr.p; tmpApiConnectptr.i = TapiIndex; c_counters.ccommitCount = TcommitCount + 1; apiConnectptr.i = TnewApiIndex; ptrCheckGuard(apiConnectptr, TapiConnectFilesize, localApiConnectRecord); copyApi(signal); if (TapiFailState != ZTRUE) { return; } else { jam(); handleApiFailState(signal, tmpApiConnectptr.i); return; }//if }//Dbtc::sendApiCommit() /* ========================================================================= */ /* ======= COPY_API ======= */ /* COPY API RECORD ALSO RESET THE OLD API RECORD SO THAT IT */ /* IS PREPARED TO RECEIVE A NEW TRANSACTION. */ /*===========================================================================*/ void Dbtc::copyApi(Signal* signal) { ApiConnectRecord * const regApiPtr = apiConnectptr.p; ApiConnectRecord * const regTmpApiPtr = tmpApiConnectptr.p; UintR TndbapiConnect = regTmpApiPtr->ndbapiConnect; UintR TfirstTcConnect = regTmpApiPtr->firstTcConnect; UintR Ttransid1 = regTmpApiPtr->transid[0]; UintR Ttransid2 = regTmpApiPtr->transid[1]; UintR Tlqhkeyconfrec = regTmpApiPtr->lqhkeyconfrec; UintR TgcpPointer = regTmpApiPtr->gcpPointer; UintR TgcpFilesize = cgcpFilesize; UintR TcommitAckMarker = regTmpApiPtr->commitAckMarker; NdbNodeBitmask Tnodes = regTmpApiPtr->m_transaction_nodes; GcpRecord *localGcpRecord = gcpRecord; regApiPtr->ndbapiBlockref = regTmpApiPtr->ndbapiBlockref; regApiPtr->ndbapiConnect = TndbapiConnect; regApiPtr->firstTcConnect = TfirstTcConnect; regApiPtr->apiConnectstate = CS_COMPLETING; regApiPtr->transid[0] = Ttransid1; regApiPtr->transid[1] = Ttransid2; regApiPtr->lqhkeyconfrec = Tlqhkeyconfrec; regApiPtr->commitAckMarker = TcommitAckMarker; regApiPtr->m_transaction_nodes = Tnodes; regApiPtr->singleUserMode = 0; gcpPtr.i = TgcpPointer; ptrCheckGuard(gcpPtr, TgcpFilesize, localGcpRecord); unlinkApiConnect(signal); linkApiToGcp(signal); setApiConTimer(tmpApiConnectptr.i, 0, __LINE__); regTmpApiPtr->apiConnectstate = CS_CONNECTED; regTmpApiPtr->commitAckMarker = RNIL; regTmpApiPtr->firstTcConnect = RNIL; regTmpApiPtr->lastTcConnect = RNIL; regTmpApiPtr->m_transaction_nodes.clear(); regTmpApiPtr->singleUserMode = 0; releaseAllSeizedIndexOperations(regTmpApiPtr); }//Dbtc::copyApi() void Dbtc::unlinkApiConnect(Signal* signal) { ApiConnectRecordPtr localApiConnectptr; ApiConnectRecord * const regTmpApiPtr = tmpApiConnectptr.p; UintR TapiConnectFilesize = capiConnectFilesize; UintR TprevGcpConnect = regTmpApiPtr->prevGcpConnect; UintR TnextGcpConnect = regTmpApiPtr->nextGcpConnect; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; if (TprevGcpConnect == RNIL) { gcpPtr.p->firstApiConnect = TnextGcpConnect; jam(); } else { localApiConnectptr.i = TprevGcpConnect; jam(); ptrCheckGuard(localApiConnectptr, TapiConnectFilesize, localApiConnectRecord); localApiConnectptr.p->nextGcpConnect = TnextGcpConnect; }//if if (TnextGcpConnect == RNIL) { gcpPtr.p->lastApiConnect = TprevGcpConnect; jam(); } else { localApiConnectptr.i = TnextGcpConnect; jam(); ptrCheckGuard(localApiConnectptr, TapiConnectFilesize, localApiConnectRecord); localApiConnectptr.p->prevGcpConnect = TprevGcpConnect; }//if }//Dbtc::unlinkApiConnect() void Dbtc::complete010Lab(Signal* signal) { TcConnectRecordPtr localTcConnectptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TtcConnectFilesize = ctcConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; localTcConnectptr.p = tcConnectptr.p; setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); UintR TapiConnectptrIndex = apiConnectptr.i; UintR Tcount = 0; do { localTcConnectptr.p->apiConnect = TapiConnectptrIndex; localTcConnectptr.p->tcConnectstate = OS_COMPLETING; /* ************ */ /* COMPLETE < */ /* ************ */ const Uint32 nextTcConnect = localTcConnectptr.p->nextTcConnect; sendCompleteLqh(signal, localTcConnectptr.p); localTcConnectptr.i = nextTcConnect; if (localTcConnectptr.i != RNIL) { Tcount++; if (Tcount < 16) { ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); jam(); continue; } else { jam(); if (ERROR_INSERTED(8013)) { CLEAR_ERROR_INSERT_VALUE; return; }//if signal->theData[0] = TcContinueB::ZSEND_COMPLETE_LOOP; signal->theData[1] = apiConnectptr.i; signal->theData[2] = localTcConnectptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); return; }//if } else { jam(); regApiPtr->apiConnectstate = CS_COMPLETE_SENT; return; }//if } while (1); }//Dbtc::complete010Lab() void Dbtc::sendCompleteLqh(Signal* signal, TcConnectRecord * const regTcPtr) { HostRecordPtr Thostptr; UintR ThostFilesize = chostFilesize; ApiConnectRecord * const regApiPtr = apiConnectptr.p; Thostptr.i = regTcPtr->lastLqhNodeId; ptrCheckGuard(Thostptr, ThostFilesize, hostRecord); if (Thostptr.p->noOfPackedWordsLqh > 22) { jam(); sendPackedSignalLqh(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if UintR Tindex = Thostptr.p->noOfPackedWordsLqh; UintR* TDataPtr = &Thostptr.p->packedWordsLqh[Tindex]; UintR Tdata1 = regTcPtr->lastLqhCon | (ZCOMPLETE << 28); UintR Tdata2 = regApiPtr->transid[0]; UintR Tdata3 = regApiPtr->transid[1]; TDataPtr[0] = Tdata1; TDataPtr[1] = Tdata2; TDataPtr[2] = Tdata3; Thostptr.p->noOfPackedWordsLqh = Tindex + 3; }//Dbtc::sendCompleteLqh() void Dbtc::execTC_COMMIT_ACK(Signal* signal){ jamEntry(); CommitAckMarker key; key.transid1 = signal->theData[0]; key.transid2 = signal->theData[1]; CommitAckMarkerPtr removedMarker; m_commitAckMarkerHash.remove(removedMarker, key); if (removedMarker.i == RNIL) { jam(); warningHandlerLab(signal, __LINE__); return; }//if sendRemoveMarkers(signal, removedMarker.p); m_commitAckMarkerPool.release(removedMarker); } void Dbtc::sendRemoveMarkers(Signal* signal, const CommitAckMarker * marker){ jam(); const Uint32 noOfLqhs = marker->noOfLqhs; const Uint32 transId1 = marker->transid1; const Uint32 transId2 = marker->transid2; for(Uint32 i = 0; ilqhNodeId[i]; sendRemoveMarker(signal, nodeId, transId1, transId2); } } void Dbtc::sendRemoveMarker(Signal* signal, NodeId nodeId, Uint32 transid1, Uint32 transid2){ /** * Seize host ptr */ HostRecordPtr hostPtr; const UintR ThostFilesize = chostFilesize; hostPtr.i = nodeId; ptrCheckGuard(hostPtr, ThostFilesize, hostRecord); if (hostPtr.p->noOfPackedWordsLqh > (25 - 3)){ jam(); sendPackedSignalLqh(signal, hostPtr.p); } else { jam(); updatePackedList(signal, hostPtr.p, hostPtr.i); }//if UintR numWord = hostPtr.p->noOfPackedWordsLqh; UintR* dataPtr = &hostPtr.p->packedWordsLqh[numWord]; dataPtr[0] = (ZREMOVE_MARKER << 28); dataPtr[1] = transid1; dataPtr[2] = transid2; hostPtr.p->noOfPackedWordsLqh = numWord + 3; } void Dbtc::execCOMPLETED(Signal* signal) { TcConnectRecordPtr localTcConnectptr; ApiConnectRecordPtr localApiConnectptr; UintR TtcConnectFilesize = ctcConnectFilesize; UintR TapiConnectFilesize = capiConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; ApiConnectRecord *localApiConnectRecord = apiConnectRecord; #ifdef ERROR_INSERT if (ERROR_INSERTED(8031)) { systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8019)) { CLEAR_ERROR_INSERT_VALUE; return; }//if if (ERROR_INSERTED(8027)) { SET_ERROR_INSERT_VALUE(8028); return; }//if if (ERROR_INSERTED(8043)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMPLETED, signal, 2000, 3); return; }//if if (ERROR_INSERTED(8044)) { SET_ERROR_INSERT_VALUE(8047); sendSignalWithDelay(cownref, GSN_COMPLETED, signal, 2000, 3); return; }//if #endif localTcConnectptr.i = signal->theData[0]; jamEntry(); ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); bool Tcond1 = (localTcConnectptr.p->tcConnectstate != OS_COMPLETING); localApiConnectptr.i = localTcConnectptr.p->apiConnect; if (Tcond1) { warningReport(signal, 6); return; }//if ptrCheckGuard(localApiConnectptr, TapiConnectFilesize, localApiConnectRecord); UintR Tdata1 = localApiConnectptr.p->transid[0] - signal->theData[1]; UintR Tdata2 = localApiConnectptr.p->transid[1] - signal->theData[2]; UintR Tcounter = localApiConnectptr.p->counter - 1; ConnectionState TapiConnectstate = localApiConnectptr.p->apiConnectstate; Tdata1 = Tdata1 | Tdata2; bool TcheckCondition = (TapiConnectstate != CS_COMPLETE_SENT) || (Tcounter != 0); if (Tdata1 != 0) { warningReport(signal, 7); return; }//if setApiConTimer(localApiConnectptr.i, ctcTimer, __LINE__); localApiConnectptr.p->counter = Tcounter; localTcConnectptr.p->tcConnectstate = OS_COMPLETED; localTcConnectptr.p->noOfNodes = 0; // == releaseNodes(signal) if (TcheckCondition) { jam(); /*-------------------------------------------------------*/ // We have not sent all COMPLETE requests yet. We could be // in the state that all sent are COMPLETED but we are // still waiting for a CONTINUEB to send the rest of the // COMPLETE requests. /*-------------------------------------------------------*/ return; }//if if (ERROR_INSERTED(8021)) { jam(); systemErrorLab(signal, __LINE__); }//if apiConnectptr = localApiConnectptr; releaseTransResources(signal); }//Dbtc::execCOMPLETED() /*---------------------------------------------------------------------------*/ /* RELEASE_TRANS_RESOURCES */ /* RELEASE ALL RESOURCES THAT ARE CONNECTED TO THIS TRANSACTION. */ /*---------------------------------------------------------------------------*/ void Dbtc::releaseTransResources(Signal* signal) { TcConnectRecordPtr localTcConnectptr; UintR TtcConnectFilesize = ctcConnectFilesize; TcConnectRecord *localTcConnectRecord = tcConnectRecord; apiConnectptr.p->m_transaction_nodes.clear(); localTcConnectptr.i = apiConnectptr.p->firstTcConnect; do { jam(); ptrCheckGuard(localTcConnectptr, TtcConnectFilesize, localTcConnectRecord); UintR rtrTcConnectptrIndex = localTcConnectptr.p->nextTcConnect; tcConnectptr.i = localTcConnectptr.i; tcConnectptr.p = localTcConnectptr.p; localTcConnectptr.i = rtrTcConnectptrIndex; releaseTcCon(); } while (localTcConnectptr.i != RNIL); handleGcp(signal); releaseFiredTriggerData(&apiConnectptr.p->theFiredTriggers); releaseAllSeizedIndexOperations(apiConnectptr.p); releaseApiConCopy(signal); }//Dbtc::releaseTransResources() /* *********************************************************************>> */ /* MODULE: HANDLE_GCP */ /* DESCRIPTION: HANDLES GLOBAL CHECKPOINT HANDLING AT THE COMPLETION */ /* OF THE COMMIT PHASE AND THE ABORT PHASE. WE MUST ENSURE THAT TC */ /* SENDS GCP_TCFINISHED WHEN ALL TRANSACTIONS BELONGING TO A CERTAIN */ /* GLOBAL CHECKPOINT HAVE COMPLETED. */ /* *********************************************************************>> */ void Dbtc::handleGcp(Signal* signal) { GcpRecord *localGcpRecord = gcpRecord; GcpRecordPtr localGcpPtr; UintR TapiConnectptrIndex = apiConnectptr.i; UintR TgcpFilesize = cgcpFilesize; localGcpPtr.i = apiConnectptr.p->gcpPointer; tmpApiConnectptr.i = TapiConnectptrIndex; tmpApiConnectptr.p = apiConnectptr.p; ptrCheckGuard(localGcpPtr, TgcpFilesize, localGcpRecord); gcpPtr.i = localGcpPtr.i; gcpPtr.p = localGcpPtr.p; unlinkApiConnect(signal); if (localGcpPtr.p->firstApiConnect == RNIL) { if (localGcpPtr.p->gcpNomoretransRec == ZTRUE) { jam(); tcheckGcpId = localGcpPtr.p->gcpId; gcpTcfinished(signal); unlinkGcp(signal); }//if }//if }//Dbtc::handleGcp() void Dbtc::releaseApiConCopy(Signal* signal) { ApiConnectRecord * const regApiPtr = apiConnectptr.p; UintR TfirstfreeApiConnectCopyOld = cfirstfreeApiConnectCopy; cfirstfreeApiConnectCopy = apiConnectptr.i; regApiPtr->nextApiConnect = TfirstfreeApiConnectCopyOld; setApiConTimer(apiConnectptr.i, 0, __LINE__); regApiPtr->apiConnectstate = CS_RESTART; }//Dbtc::releaseApiConCopy() /* ========================================================================= */ /* ------- RELEASE ALL RECORDS CONNECTED TO A DIRTY WRITE OPERATION ------- */ /* ========================================================================= */ void Dbtc::releaseDirtyWrite(Signal* signal) { unlinkReadyTcCon(signal); releaseTcCon(); ApiConnectRecord * const regApiPtr = apiConnectptr.p; if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { if (regApiPtr->firstTcConnect == RNIL) { jam(); regApiPtr->apiConnectstate = CS_CONNECTED; setApiConTimer(apiConnectptr.i, 0, __LINE__); sendtckeyconf(signal, 1); }//if }//if }//Dbtc::releaseDirtyWrite() /***************************************************************************** * L Q H K E Y R E F * WHEN LQHKEYREF IS RECEIVED DBTC WILL CHECK IF COMMIT FLAG WAS SENT FROM THE * APPLICATION. IF SO, THE WHOLE TRANSACTION WILL BE ROLLED BACK AND SIGNAL * TCROLLBACKREP WILL BE SENT TO THE API. * * OTHERWISE TC WILL CHECK THE ERRORCODE. IF THE ERRORCODE IS INDICATING THAT * THE "ROW IS NOT FOUND" FOR UPDATE/READ/DELETE OPERATIONS AND "ROW ALREADY * EXISTS" FOR INSERT OPERATIONS, DBTC WILL RELEASE THE OPERATION AND THEN * SEND RETURN SIGNAL TCKEYREF TO THE USER. THE USER THEN HAVE TO SEND * SIGNAL TC_COMMITREQ OR TC_ROLLBACKREQ TO CONCLUDE THE TRANSACTION. * IF ANY TCKEYREQ WITH COMMIT IS RECEIVED AND API_CONNECTSTATE EQUALS * "REC_LQHREFUSE", * THE OPERATION WILL BE TREATED AS AN OPERATION WITHOUT COMMIT. WHEN ANY * OTHER FAULTCODE IS RECEIVED THE WHOLE TRANSACTION MUST BE ROLLED BACK *****************************************************************************/ void Dbtc::execLQHKEYREF(Signal* signal) { const LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtr(); Uint32 indexId = 0; jamEntry(); UintR compare_transid1, compare_transid2; UintR TtcConnectFilesize = ctcConnectFilesize; /*------------------------------------------------------------------------- * * RELEASE NODE BUFFER(S) TO INDICATE THAT THIS OPERATION HAVE NO * TRANSACTION PARTS ACTIVE ANYMORE. * LQHKEYREF HAVE CLEARED ALL PARTS ON ITS PATH BACK TO TC. *-------------------------------------------------------------------------*/ if (lqhKeyRef->connectPtr < TtcConnectFilesize) { /*----------------------------------------------------------------------- * WE HAVE TO CHECK THAT THE TRANSACTION IS STILL VALID. FIRST WE CHECK * THAT THE LQH IS STILL CONNECTED TO A TC, IF THIS HOLDS TRUE THEN THE * TC MUST BE CONNECTED TO AN API CONNECT RECORD. * WE MUST ENSURE THAT THE TRANSACTION ID OF THIS API CONNECT * RECORD IS STILL THE SAME AS THE ONE LQHKEYREF REFERS TO. * IF NOT SIMPLY EXIT AND FORGET THE SIGNAL SINCE THE TRANSACTION IS * ALREADY COMPLETED (ABORTED). *-----------------------------------------------------------------------*/ tcConnectptr.i = lqhKeyRef->connectPtr; Uint32 errCode = terrorCode = lqhKeyRef->errorCode; ptrAss(tcConnectptr, tcConnectRecord); TcConnectRecord * const regTcPtr = tcConnectptr.p; if (regTcPtr->tcConnectstate == OS_OPERATING) { Uint32 save = apiConnectptr.i = regTcPtr->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ApiConnectRecord * const regApiPtr = apiConnectptr.p; compare_transid1 = regApiPtr->transid[0] ^ lqhKeyRef->transId1; compare_transid2 = regApiPtr->transid[1] ^ lqhKeyRef->transId2; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 25); return; }//if const ConnectionState state = regApiPtr->apiConnectstate; const Uint32 triggeringOp = regTcPtr->triggeringOperation; if (triggeringOp != RNIL) { jam(); // This operation was created by a trigger execting operation TcConnectRecordPtr opPtr; TcConnectRecord *localTcConnectRecord = tcConnectRecord; const Uint32 currentIndexId = regTcPtr->currentIndexId; ndbassert(currentIndexId != 0); // Only index triggers so far opPtr.i = triggeringOp; ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord); // The operation executed an index trigger TcIndexData* indexData = c_theIndexes.getPtr(currentIndexId); indexId = indexData->indexId; regApiPtr->errorData = indexId; const Uint32 opType = regTcPtr->operation; if (errCode == ZALREADYEXIST) errCode = terrorCode = ZNOTUNIQUE; else if (!(opType == ZDELETE && errCode == ZNOT_FOUND)) { jam(); /** * "Normal path" */ // fall-through } else { jam(); /** ZDELETE && NOT_FOUND */ if(indexData->indexState == IS_BUILDING && state != CS_ABORTING){ jam(); /** * Ignore error */ regApiPtr->lqhkeyconfrec++; unlinkReadyTcCon(signal); releaseTcCon(); opPtr.p->triggerExecutionCount--; if (opPtr.p->triggerExecutionCount == 0) { /** * We have completed current trigger execution * Continue triggering operation */ jam(); continueTriggeringOp(signal, opPtr.p); } return; } } } Uint32 marker = regTcPtr->commitAckMarker; markOperationAborted(regApiPtr, regTcPtr); if(regApiPtr->apiConnectstate == CS_ABORTING){ /** * We're already aborting' so don't send an "extra" TCKEYREF */ jam(); return; } const Uint32 abort = regTcPtr->m_execAbortOption; if (abort == TcKeyReq::AbortOnError || triggeringOp != RNIL) { /** * No error is allowed on this operation */ TCKEY_abort(signal, 49); return; }//if if (marker != RNIL){ /** * This was an insert/update/delete/write which failed * that contained the marker * Currently unsupported to place new marker */ TCKEY_abort(signal, 49); return; } /* Only ref in certain situations */ { const Uint32 opType = regTcPtr->operation; if ( (opType == ZDELETE && errCode != ZNOT_FOUND) || (opType == ZINSERT && errCode != ZALREADYEXIST) || (opType == ZUPDATE && errCode != ZNOT_FOUND) || (opType == ZWRITE && errCode != 839 && errCode != 840)) { TCKEY_abort(signal, 49); return; } } /* *************** */ /* TCKEYREF < */ /* *************** */ TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); tcKeyRef->transId[0] = regApiPtr->transid[0]; tcKeyRef->transId[1] = regApiPtr->transid[1]; tcKeyRef->errorCode = terrorCode; bool isIndexOp = regTcPtr->isIndexOp; Uint32 indexOp = tcConnectptr.p->indexOp; Uint32 clientData = regTcPtr->clientData; unlinkReadyTcCon(signal); /* LINK TC CONNECT RECORD OUT OF */ releaseTcCon(); /* RELEASE THE TC CONNECT RECORD */ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); if (isIndexOp) { jam(); regApiPtr->lqhkeyreqrec--; // Compensate for extra during read tcKeyRef->connectPtr = indexOp; tcKeyRef->errorData = indexId; EXECUTE_DIRECT(DBTC, GSN_TCKEYREF, signal, TcKeyRef::SignalLength); apiConnectptr.i = save; apiConnectptr.p = regApiPtr; } else { jam(); tcKeyRef->connectPtr = clientData; tcKeyRef->errorData = indexId; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); }//if /*--------------------------------------------------------------------- * SINCE WE ARE NOT ABORTING WE NEED TO UPDATE THE COUNT OF HOW MANY * LQHKEYREQ THAT HAVE RETURNED. * IF NO MORE OUTSTANDING LQHKEYREQ'S THEN WE NEED TO * TCKEYCONF (IF THERE IS ANYTHING TO SEND). *---------------------------------------------------------------------*/ regApiPtr->lqhkeyreqrec--; if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) { if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { jam(); diverify010Lab(signal); return; } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) { jam(); sendtckeyconf(signal, 2); return; } }//if return; } else { warningReport(signal, 26); }//if } else { errorReport(signal, 6); }//if return; }//Dbtc::execLQHKEYREF() void Dbtc::clearCommitAckMarker(ApiConnectRecord * const regApiPtr, TcConnectRecord * const regTcPtr) { const Uint32 commitAckMarker = regTcPtr->commitAckMarker; if (regApiPtr->commitAckMarker == RNIL) ndbassert(commitAckMarker == RNIL); if (commitAckMarker != RNIL) ndbassert(regApiPtr->commitAckMarker != RNIL); if(commitAckMarker != RNIL){ jam(); m_commitAckMarkerHash.release(commitAckMarker); regTcPtr->commitAckMarker = RNIL; regApiPtr->commitAckMarker = RNIL; } } void Dbtc::markOperationAborted(ApiConnectRecord * const regApiPtr, TcConnectRecord * const regTcPtr) { /*------------------------------------------------------------------------ * RELEASE NODES TO INDICATE THAT THE OPERATION IS ALREADY ABORTED IN THE * LQH'S ALSO SET STATE TO ABORTING TO INDICATE THE ABORT IS * ALREADY COMPLETED. *------------------------------------------------------------------------*/ regTcPtr->noOfNodes = 0; // == releaseNodes(signal) regTcPtr->tcConnectstate = OS_ABORTING; clearCommitAckMarker(regApiPtr, regTcPtr); } /*--------------------------------------*/ /* EXIT AND WAIT FOR SIGNAL TCOMMITREQ */ /* OR TCROLLBACKREQ FROM THE USER TO */ /* CONTINUE THE TRANSACTION */ /*--------------------------------------*/ void Dbtc::execTC_COMMITREQ(Signal* signal) { UintR compare_transid1, compare_transid2; jamEntry(); apiConnectptr.i = signal->theData[0]; if (apiConnectptr.i < capiConnectFilesize) { ptrAss(apiConnectptr, apiConnectRecord); compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { jam(); return; }//if ApiConnectRecord * const regApiPtr = apiConnectptr.p; const Uint32 apiConnectPtr = regApiPtr->ndbapiConnect; const Uint32 apiBlockRef = regApiPtr->ndbapiBlockref; const Uint32 transId1 = regApiPtr->transid[0]; const Uint32 transId2 = regApiPtr->transid[1]; Uint32 errorCode = 0; regApiPtr->m_exec_flag = 1; switch (regApiPtr->apiConnectstate) { case CS_STARTED: tcConnectptr.i = regApiPtr->firstTcConnect; if (tcConnectptr.i != RNIL) { ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) { jam(); /*******************************************************************/ // The proper case where the application is waiting for commit or // abort order. // Start the commit order. /*******************************************************************/ regApiPtr->returnsignal = RS_TC_COMMITCONF; setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); diverify010Lab(signal); return; } else { jam(); /*******************************************************************/ // The transaction is started but not all operations are completed. // It is not possible to commit the transaction in this state. // We will abort it instead. /*******************************************************************/ regApiPtr->returnsignal = RS_NO_RETURN; errorCode = ZTRANS_STATUS_ERROR; abort010Lab(signal); }//if } else { jam(); /** * No operations, accept commit */ TcCommitConf * const commitConf = (TcCommitConf *)&signal->theData[0]; commitConf->apiConnectPtr = apiConnectPtr; commitConf->transId1 = transId1; commitConf->transId2 = transId2; commitConf->gci = 0; sendSignal(apiBlockRef, GSN_TC_COMMITCONF, signal, TcCommitConf::SignalLength, JBB); regApiPtr->returnsignal = RS_NO_RETURN; releaseAbortResources(signal); return; }//if break; case CS_RECEIVING: jam(); /***********************************************************************/ // A transaction is still receiving data. We cannot commit an unfinished // transaction. We will abort it instead. /***********************************************************************/ regApiPtr->returnsignal = RS_NO_RETURN; errorCode = ZPREPAREINPROGRESS; abort010Lab(signal); break; case CS_START_COMMITTING: case CS_COMMITTING: case CS_COMMIT_SENT: case CS_COMPLETING: case CS_COMPLETE_SENT: case CS_REC_COMMITTING: case CS_PREPARE_TO_COMMIT: jam(); /***********************************************************************/ // The transaction is already performing a commit but it is not concluded // yet. /***********************************************************************/ errorCode = ZCOMMITINPROGRESS; break; case CS_ABORTING: jam(); errorCode = regApiPtr->returncode ? regApiPtr->returncode : ZABORTINPROGRESS; break; case CS_START_SCAN: jam(); /***********************************************************************/ // The transaction is a scan. Scans cannot commit /***********************************************************************/ errorCode = ZSCANINPROGRESS; break; case CS_PREPARED: jam(); return; case CS_START_PREPARING: jam(); return; case CS_REC_PREPARING: jam(); return; break; default: warningHandlerLab(signal, __LINE__); return; }//switch TcCommitRef * const commitRef = (TcCommitRef*)&signal->theData[0]; commitRef->apiConnectPtr = apiConnectPtr; commitRef->transId1 = transId1; commitRef->transId2 = transId2; commitRef->errorCode = errorCode; sendSignal(apiBlockRef, GSN_TC_COMMITREF, signal, TcCommitRef::SignalLength, JBB); return; } else /** apiConnectptr.i < capiConnectFilesize */ { jam(); warningHandlerLab(signal, __LINE__); return; } }//Dbtc::execTC_COMMITREQ() /** * TCROLLBACKREQ * * Format is: * * thedata[0] = apiconnectptr * thedata[1] = transid[0] * thedata[2] = transid[1] * OPTIONAL thedata[3] = flags * * Flags: * 0x1 = potentiallyBad data from API (try not to assert) */ void Dbtc::execTCROLLBACKREQ(Signal* signal) { bool potentiallyBad= false; UintR compare_transid1, compare_transid2; jamEntry(); if(unlikely((signal->getLength() >= 4) && (signal->theData[3] & 0x1))) { ndbout_c("Trying to roll back potentially bad txn\n"); potentiallyBad= true; } apiConnectptr.i = signal->theData[0]; if (apiConnectptr.i >= capiConnectFilesize) { goto TC_ROLL_warning; }//if ptrAss(apiConnectptr, apiConnectRecord); compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { jam(); return; }//if apiConnectptr.p->m_exec_flag = 1; switch (apiConnectptr.p->apiConnectstate) { case CS_STARTED: case CS_RECEIVING: jam(); apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF; abort010Lab(signal); return; case CS_CONNECTED: jam(); signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKCONF, signal, 3, JBB); break; case CS_START_SCAN: case CS_PREPARE_TO_COMMIT: case CS_COMMITTING: case CS_COMMIT_SENT: case CS_COMPLETING: case CS_COMPLETE_SENT: case CS_WAIT_COMMIT_CONF: case CS_WAIT_COMPLETE_CONF: case CS_RESTART: case CS_DISCONNECTED: case CS_START_COMMITTING: case CS_REC_COMMITTING: jam(); /* ***************< */ /* TC_ROLLBACKREF < */ /* ***************< */ signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; signal->theData[3] = ZROLLBACKNOTALLOWED; signal->theData[4] = apiConnectptr.p->apiConnectstate; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREF, signal, 5, JBB); break; /* SEND A REFUSAL SIGNAL*/ case CS_ABORTING: jam(); if (apiConnectptr.p->abortState == AS_IDLE) { jam(); signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKCONF, signal, 3, JBB); } else { jam(); apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF; }//if break; case CS_WAIT_ABORT_CONF: jam(); apiConnectptr.p->returnsignal = RS_TCROLLBACKCONF; break; case CS_START_PREPARING: jam(); case CS_PREPARED: jam(); case CS_REC_PREPARING: jam(); default: goto TC_ROLL_system_error; break; }//switch return; TC_ROLL_warning: jam(); if(likely(potentiallyBad==false)) warningHandlerLab(signal, __LINE__); return; TC_ROLL_system_error: jam(); if(likely(potentiallyBad==false)) systemErrorLab(signal, __LINE__); return; }//Dbtc::execTCROLLBACKREQ() void Dbtc::execTC_HBREP(Signal* signal) { const TcHbRep * const tcHbRep = (TcHbRep *)signal->getDataPtr(); jamEntry(); apiConnectptr.i = tcHbRep->apiConnectPtr; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); if (apiConnectptr.p->transid[0] == tcHbRep->transId1 && apiConnectptr.p->transid[1] == tcHbRep->transId2){ if (getApiConTimer(apiConnectptr.i) != 0){ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); } else { DEBUG("TCHBREP received when timer was off apiConnectptr.i=" << apiConnectptr.i); } } }//Dbtc::execTCHBREP() /* 4.3.15 ABORT ----------- */ /*****************************************************************************/ /* A B O R T */ /* */ /*****************************************************************************/ void Dbtc::warningReport(Signal* signal, int place) { switch (place) { case 0: jam(); #ifdef ABORT_TRACE ndbout << "ABORTED to not active TC record" << endl; #endif break; case 1: jam(); #ifdef ABORT_TRACE ndbout << "ABORTED to TC record active with new transaction" << endl; #endif break; case 2: jam(); #ifdef ABORT_TRACE ndbout << "ABORTED to active TC record not expecting ABORTED" << endl; #endif break; case 3: jam(); #ifdef ABORT_TRACE ndbout << "ABORTED to TC rec active with trans but wrong node" << endl; ndbout << "This is ok when aborting in node failure situations" << endl; #endif break; case 4: jam(); #ifdef ABORT_TRACE ndbout << "Received COMMITTED in wrong state in Dbtc" << endl; #endif break; case 5: jam(); #ifdef ABORT_TRACE ndbout << "Received COMMITTED with wrong transid in Dbtc" << endl; #endif break; case 6: jam(); #ifdef ABORT_TRACE ndbout << "Received COMPLETED in wrong state in Dbtc" << endl; #endif break; case 7: jam(); #ifdef ABORT_TRACE ndbout << "Received COMPLETED with wrong transid in Dbtc" << endl; #endif break; case 8: jam(); #ifdef ABORT_TRACE ndbout << "Received COMMITCONF with tc-rec in wrong state in Dbtc" << endl; #endif break; case 9: jam(); #ifdef ABORT_TRACE ndbout << "Received COMMITCONF with api-rec in wrong state in Dbtc" <theData[0]; UintR Tnodeid = signal->theData[3]; UintR TlastLqhInd = signal->theData[4]; if (ERROR_INSERTED(8040)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_ABORTED, signal, 2000, 5); return; }//if /*------------------------------------------------------------------------ * ONE PARTICIPANT IN THE TRANSACTION HAS REPORTED THAT IT IS ABORTED. *------------------------------------------------------------------------*/ if (tcConnectptr.i >= ctcConnectFilesize) { errorReport(signal, 0); return; }//if /*------------------------------------------------------------------------- * WE HAVE TO CHECK THAT THIS IS NOT AN OLD SIGNAL BELONGING TO A * TRANSACTION ALREADY ABORTED. THIS CAN HAPPEN WHEN TIME-OUT OCCURS * IN TC WAITING FOR ABORTED. *-------------------------------------------------------------------------*/ ptrAss(tcConnectptr, tcConnectRecord); if (tcConnectptr.p->tcConnectstate != OS_ABORT_SENT) { warningReport(signal, 2); return; /*-----------------------------------------------------------------------*/ // ABORTED reported on an operation not expecting ABORT. /*-----------------------------------------------------------------------*/ }//if apiConnectptr.i = tcConnectptr.p->apiConnect; if (apiConnectptr.i >= capiConnectFilesize) { warningReport(signal, 0); return; }//if ptrAss(apiConnectptr, apiConnectRecord); compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[1]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[2]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 1); return; }//if if (ERROR_INSERTED(8024)) { jam(); systemErrorLab(signal, __LINE__); }//if /** * Release marker */ clearCommitAckMarker(apiConnectptr.p, tcConnectptr.p); Uint32 i; Uint32 Tfound = 0; for (i = 0; i < tcConnectptr.p->noOfNodes; i++) { jam(); if (tcConnectptr.p->tcNodedata[i] == Tnodeid) { /*--------------------------------------------------------------------- * We have received ABORTED from one of the participants in this * operation in this aborted transaction. * Record all nodes that have completed abort. * If last indicator is set it means that no more replica has * heard of the operation and are thus also aborted. *---------------------------------------------------------------------*/ jam(); Tfound = 1; clearTcNodeData(signal, TlastLqhInd, i); }//if }//for if (Tfound == 0) { warningReport(signal, 3); return; } for (i = 0; i < tcConnectptr.p->noOfNodes; i++) { if (tcConnectptr.p->tcNodedata[i] != 0) { /*-------------------------------------------------------------------- * There are still outstanding ABORTED's to wait for. *--------------------------------------------------------------------*/ jam(); return; }//if }//for tcConnectptr.p->noOfNodes = 0; tcConnectptr.p->tcConnectstate = OS_ABORTING; setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); apiConnectptr.p->counter--; if (apiConnectptr.p->counter > 0) { jam(); /*---------------------------------------------------------------------- * WE ARE STILL WAITING FOR MORE PARTICIPANTS TO SEND ABORTED. *----------------------------------------------------------------------*/ return; }//if /*------------------------------------------------------------------------*/ /* */ /* WE HAVE NOW COMPLETED THE ABORT PROCESS. WE HAVE RECEIVED ABORTED */ /* FROM ALL PARTICIPANTS IN THE TRANSACTION. WE CAN NOW RELEASE ALL */ /* RESOURCES CONNECTED TO THE TRANSACTION AND SEND THE ABORT RESPONSE */ /*------------------------------------------------------------------------*/ releaseAbortResources(signal); }//Dbtc::execABORTED() void Dbtc::clearTcNodeData(Signal* signal, UintR TLastLqhIndicator, UintR Tstart) { UintR Ti; if (TLastLqhIndicator == ZTRUE) { for (Ti = Tstart ; Ti < tcConnectptr.p->noOfNodes; Ti++) { jam(); tcConnectptr.p->tcNodedata[Ti] = 0; }//for } else { jam(); tcConnectptr.p->tcNodedata[Tstart] = 0; }//for }//clearTcNodeData() void Dbtc::abortErrorLab(Signal* signal) { ptrGuard(apiConnectptr); ApiConnectRecord * transP = apiConnectptr.p; if (transP->apiConnectstate == CS_ABORTING && transP->abortState != AS_IDLE){ jam(); return; } transP->returnsignal = RS_TCROLLBACKREP; if(transP->returncode == 0){ jam(); transP->returncode = terrorCode; } abort010Lab(signal); }//Dbtc::abortErrorLab() void Dbtc::abort010Lab(Signal* signal) { ApiConnectRecord * transP = apiConnectptr.p; if (transP->apiConnectstate == CS_ABORTING && transP->abortState != AS_IDLE){ jam(); return; } transP->apiConnectstate = CS_ABORTING; /*------------------------------------------------------------------------*/ /* AN ABORT DECISION HAS BEEN TAKEN FOR SOME REASON. WE NEED TO ABORT */ /* ALL PARTICIPANTS IN THE TRANSACTION. */ /*------------------------------------------------------------------------*/ transP->abortState = AS_ACTIVE; transP->counter = 0; if (transP->firstTcConnect == RNIL) { jam(); /*--------------------------------------------------------------------*/ /* WE HAVE NO PARTICIPANTS IN THE TRANSACTION. */ /*--------------------------------------------------------------------*/ releaseAbortResources(signal); return; }//if tcConnectptr.i = transP->firstTcConnect; abort015Lab(signal); }//Dbtc::abort010Lab() /*--------------------------------------------------------------------------*/ /* */ /* WE WILL ABORT ONE NODE PER OPERATION AT A TIME. THIS IS TO KEEP */ /* ERROR HANDLING OF THIS PROCESS FAIRLY SIMPLE AND TRACTABLE. */ /* EVEN IF NO NODE OF THIS PARTICULAR NODE NUMBER NEEDS ABORTION WE */ /* MUST ENSURE THAT ALL NODES ARE CHECKED. THUS A FAULTY NODE DOES */ /* NOT MEAN THAT ALL NODES IN AN OPERATION IS ABORTED. FOR THIS REASON*/ /* WE SET THE TCONTINUE_ABORT TO TRUE WHEN A FAULTY NODE IS DETECTED. */ /*--------------------------------------------------------------------------*/ void Dbtc::abort015Lab(Signal* signal) { Uint32 TloopCount = 0; ABORT020: jam(); TloopCount++; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); switch (tcConnectptr.p->tcConnectstate) { case OS_WAIT_DIH: case OS_WAIT_KEYINFO: case OS_WAIT_ATTR: jam(); /*----------------------------------------------------------------------*/ /* WE ARE STILL WAITING FOR MORE KEYINFO/ATTRINFO. WE HAVE NOT CONTACTED*/ /* ANY LQH YET AND SO WE CAN SIMPLY SET STATE TO ABORTING. */ /*----------------------------------------------------------------------*/ tcConnectptr.p->noOfNodes = 0; // == releaseAbort(signal) tcConnectptr.p->tcConnectstate = OS_ABORTING; break; case OS_CONNECTED: jam(); /*----------------------------------------------------------------------- * WE ARE STILL IN THE INITIAL PHASE OF THIS OPERATION. * NEED NOT BOTHER ABOUT ANY LQH ABORTS. *-----------------------------------------------------------------------*/ tcConnectptr.p->noOfNodes = 0; // == releaseAbort(signal) tcConnectptr.p->tcConnectstate = OS_ABORTING; break; case OS_PREPARED: jam(); case OS_OPERATING: jam(); /*---------------------------------------------------------------------- * WE HAVE SENT LQHKEYREQ AND ARE IN SOME STATE OF EITHER STILL * SENDING THE OPERATION, WAITING FOR REPLIES, WAITING FOR MORE * ATTRINFO OR OPERATION IS PREPARED. WE NEED TO ABORT ALL LQH'S. *----------------------------------------------------------------------*/ releaseAndAbort(signal); tcConnectptr.p->tcConnectstate = OS_ABORT_SENT; TloopCount += 127; break; case OS_ABORTING: jam(); break; case OS_ABORT_SENT: jam(); DEBUG("ABORT_SENT state in abort015Lab(), not expected"); systemErrorLab(signal, __LINE__); return; default: jam(); DEBUG("tcConnectstate = " << tcConnectptr.p->tcConnectstate); systemErrorLab(signal, __LINE__); return; }//switch if (tcConnectptr.p->nextTcConnect != RNIL) { jam(); tcConnectptr.i = tcConnectptr.p->nextTcConnect; if (TloopCount < 1024) { goto ABORT020; } else { jam(); /*--------------------------------------------------------------------- * Reset timer to avoid time-out in real-time break. * Increase counter to ensure that we don't think that all ABORTED have * been received before all have been sent. *---------------------------------------------------------------------*/ apiConnectptr.p->counter++; setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); signal->theData[0] = TcContinueB::ZABORT_BREAK; signal->theData[1] = tcConnectptr.i; signal->theData[2] = apiConnectptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); return; }//if }//if if (apiConnectptr.p->counter > 0) { jam(); setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); return; }//if /*----------------------------------------------------------------------- * WE HAVE NOW COMPLETED THE ABORT PROCESS. WE HAVE RECEIVED ABORTED * FROM ALL PARTICIPANTS IN THE TRANSACTION. WE CAN NOW RELEASE ALL * RESOURCES CONNECTED TO THE TRANSACTION AND SEND THE ABORT RESPONSE *------------------------------------------------------------------------*/ releaseAbortResources(signal); }//Dbtc::abort015Lab() /*--------------------------------------------------------------------------*/ /* RELEASE KEY AND ATTRINFO OBJECTS AND SEND ABORT TO THE LQH BLOCK. */ /*--------------------------------------------------------------------------*/ int Dbtc::releaseAndAbort(Signal* signal) { HostRecordPtr localHostptr; UintR TnoLoops = tcConnectptr.p->noOfNodes; apiConnectptr.p->counter++; bool prevAlive = false; for (Uint32 Ti = 0; Ti < TnoLoops ; Ti++) { localHostptr.i = tcConnectptr.p->tcNodedata[Ti]; ptrCheckGuard(localHostptr, chostFilesize, hostRecord); if (localHostptr.p->hostStatus == HS_ALIVE) { jam(); if (prevAlive) { // if previous is alive, its LQH forwards abort to this node jam(); continue; } /* ************< */ /* ABORT < */ /* ************< */ tblockref = calcLqhBlockRef(localHostptr.i); signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; signal->theData[2] = apiConnectptr.p->transid[0]; signal->theData[3] = apiConnectptr.p->transid[1]; sendSignal(tblockref, GSN_ABORT, signal, 4, JBB); prevAlive = true; } else { jam(); signal->theData[0] = tcConnectptr.i; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; signal->theData[3] = localHostptr.i; signal->theData[4] = ZFALSE; sendSignal(cownref, GSN_ABORTED, signal, 5, JBB); prevAlive = false; }//if }//for return 1; }//Dbtc::releaseAndAbort() /* ------------------------------------------------------------------------- */ /* ------- ENTER TIME_SIGNAL ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dbtc::execTIME_SIGNAL(Signal* signal) { jamEntry(); ctcTimer++; if (csystemStart != SSS_TRUE) { jam(); return; }//if checkStartTimeout(signal); checkStartFragTimeout(signal); }//Dbtc::execTIME_SIGNAL() /*------------------------------------------------*/ /* Start timeout handling if not already going on */ /*------------------------------------------------*/ void Dbtc::checkStartTimeout(Signal* signal) { ctimeOutCheckCounter++; if (ctimeOutCheckActive == TOCS_TRUE) { jam(); // Check heartbeat of timeout loop if(ctimeOutCheckHeartbeat > ctimeOutCheckLastHeartbeat){ jam(); ctimeOutMissedHeartbeats = 0; }else{ jam(); ctimeOutMissedHeartbeats++; if (ctimeOutMissedHeartbeats > 100){ jam(); systemErrorLab(signal, __LINE__); } } ctimeOutCheckLastHeartbeat = ctimeOutCheckHeartbeat; return; }//if if (ctimeOutCheckCounter < ctimeOutCheckDelay) { jam(); /*------------------------------------------------------------------*/ /* */ /* NO TIME-OUT CHECKED THIS TIME. WAIT MORE. */ /*------------------------------------------------------------------*/ return; }//if ctimeOutCheckActive = TOCS_TRUE; ctimeOutCheckCounter = 0; timeOutLoopStartLab(signal, 0); // 0 is first api connect record return; }//Dbtc::execTIME_SIGNAL() /*----------------------------------------------------------------*/ /* Start fragment (scan) timeout handling if not already going on */ /*----------------------------------------------------------------*/ void Dbtc::checkStartFragTimeout(Signal* signal) { ctimeOutCheckFragCounter++; if (ctimeOutCheckFragActive == TOCS_TRUE) { jam(); return; }//if if (ctimeOutCheckFragCounter < ctimeOutCheckDelay) { jam(); /*------------------------------------------------------------------*/ /* NO TIME-OUT CHECKED THIS TIME. WAIT MORE. */ /*------------------------------------------------------------------*/ return; }//if // Go through the fragment records and look for timeout in a scan. ctimeOutCheckFragActive = TOCS_TRUE; ctimeOutCheckFragCounter = 0; timeOutLoopStartFragLab(signal, 0); // 0 means first scan record }//checkStartFragTimeout() /*------------------------------------------------------------------*/ /* IT IS NOW TIME TO CHECK WHETHER ANY TRANSACTIONS HAVE */ /* BEEN DELAYED FOR SO LONG THAT WE ARE FORCED TO PERFORM */ /* SOME ACTION, EITHER ABORT OR RESEND OR REMOVE A NODE FROM */ /* THE WAITING PART OF A PROTOCOL. */ /* The algorithm used here is to check 1024 transactions at a time before doing a real-time break. To avoid aborting both transactions in a deadlock detected by time-out we insert a random extra time-out of upto 630 ms by using the lowest six bits of the api connect reference. We spread it out from 0 to 630 ms if base time-out is larger than 3 sec, we spread it out from 0 to 70 ms if base time-out is smaller than 300 msec, and otherwise we spread it out 310 ms. */ /*------------------------------------------------------------------*/ void Dbtc::timeOutLoopStartLab(Signal* signal, Uint32 api_con_ptr) { Uint32 end_ptr, time_passed, time_out_value, mask_value; Uint32 old_mask_value= 0; const Uint32 api_con_sz= capiConnectFilesize; const Uint32 tc_timer= ctcTimer; const Uint32 time_out_param= ctimeOutValue; const Uint32 old_time_out_param= c_abortRec.oldTimeOutValue; ctimeOutCheckHeartbeat = tc_timer; if (api_con_ptr + 1024 < api_con_sz) { jam(); end_ptr= api_con_ptr + 1024; } else { jam(); end_ptr= api_con_sz; } if (time_out_param > 300) { jam(); mask_value= 63; } else if (time_out_param < 30) { jam(); mask_value= 7; } else { jam(); mask_value= 31; } if (time_out_param != old_time_out_param && getNodeState().getSingleUserMode()) { // abort during single user mode, use old_mask_value as flag // and calculate value to be used for connections with allowed api if (old_time_out_param > 300) { jam(); old_mask_value= 63; } else if (old_time_out_param < 30) { jam(); old_mask_value= 7; } else { jam(); old_mask_value= 31; } } for ( ; api_con_ptr < end_ptr; api_con_ptr++) { Uint32 api_timer= getApiConTimer(api_con_ptr); jam(); if (api_timer != 0) { Uint32 error= ZTIME_OUT_ERROR; time_out_value= time_out_param + (ndb_rand() & mask_value); if (unlikely(old_mask_value)) // abort during single user mode { apiConnectptr.i = api_con_ptr; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); if ((getNodeState().getSingleUserApi() == refToNode(apiConnectptr.p->ndbapiBlockref)) || !(apiConnectptr.p->singleUserMode & (1 << NDB_SUM_LOCKED))) { // api allowed during single user, use original timeout time_out_value= old_time_out_param + (api_con_ptr & old_mask_value); } else { error= ZCLUSTER_IN_SINGLEUSER_MODE; } } time_passed= tc_timer - api_timer; if (time_passed > time_out_value) { jam(); timeOutFoundLab(signal, api_con_ptr, error); api_con_ptr++; break; } } } if (api_con_ptr == api_con_sz) { jam(); /*------------------------------------------------------------------*/ /* */ /* WE HAVE NOW CHECKED ALL TRANSACTIONS FOR TIME-OUT AND ALSO */ /* STARTED TIME-OUT HANDLING OF THOSE WE FOUND. WE ARE NOW */ /* READY AND CAN WAIT FOR THE NEXT TIME-OUT CHECK. */ /*------------------------------------------------------------------*/ ctimeOutCheckActive = TOCS_FALSE; } else { jam(); sendContinueTimeOutControl(signal, api_con_ptr); } return; }//Dbtc::timeOutLoopStartLab() void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr, Uint32 errCode) { apiConnectptr.i = TapiConPtr; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); /*------------------------------------------------------------------*/ /* */ /* THIS TRANSACTION HAVE EXPERIENCED A TIME-OUT AND WE NEED TO*/ /* FIND OUT WHAT WE NEED TO DO BASED ON THE STATE INFORMATION.*/ /*------------------------------------------------------------------*/ DEBUG("[ H'" << hex << apiConnectptr.p->transid[0] << " H'" << apiConnectptr.p->transid[1] << "] " << dec << "Time-out in state = " << apiConnectptr.p->apiConnectstate << " apiConnectptr.i = " << apiConnectptr.i << " - exec: " << apiConnectptr.p->m_exec_flag << " - place: " << c_apiConTimer_line[apiConnectptr.i] << " code: " << errCode); switch (apiConnectptr.p->apiConnectstate) { case CS_STARTED: if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec && errCode != ZCLUSTER_IN_SINGLEUSER_MODE){ jam(); /* We are waiting for application to continue the transaction. In this particular state we will use the application timeout parameter rather than the shorter Deadlock detection timeout. */ if (c_appl_timeout_value == 0 || (ctcTimer - getApiConTimer(apiConnectptr.i)) <= c_appl_timeout_value) { jam(); return; }//if } apiConnectptr.p->returnsignal = RS_TCROLLBACKREP; apiConnectptr.p->returncode = errCode; abort010Lab(signal); return; case CS_RECEIVING: case CS_REC_COMMITTING: case CS_START_COMMITTING: jam(); /*------------------------------------------------------------------*/ /* WE ARE STILL IN THE PREPARE PHASE AND THE TRANSACTION HAS */ /* NOT YET REACHED ITS COMMIT POINT. THUS IT IS NOW OK TO */ /* START ABORTING THE TRANSACTION. ALSO START CHECKING THE */ /* REMAINING TRANSACTIONS. */ /*------------------------------------------------------------------*/ terrorCode = errCode; abortErrorLab(signal); return; case CS_COMMITTING: jam(); /*------------------------------------------------------------------*/ // We are simply waiting for a signal in the job buffer. Only extreme // conditions should get us here. We ignore it. /*------------------------------------------------------------------*/ case CS_COMPLETING: jam(); /*------------------------------------------------------------------*/ // We are simply waiting for a signal in the job buffer. Only extreme // conditions should get us here. We ignore it. /*------------------------------------------------------------------*/ case CS_PREPARE_TO_COMMIT: { jam(); /*------------------------------------------------------------------*/ /* WE ARE WAITING FOR DIH TO COMMIT THE TRANSACTION. WE SIMPLY*/ /* KEEP WAITING SINCE THERE IS NO BETTER IDEA ON WHAT TO DO. */ /* IF IT IS BLOCKED THEN NO TRANSACTION WILL PASS THIS GATE. */ // To ensure against strange bugs we crash the system if we have passed // time-out period by a factor of 10 and it is also at least 5 seconds. /*------------------------------------------------------------------*/ Uint32 time_passed = ctcTimer - getApiConTimer(apiConnectptr.i); if (time_passed > 500 && time_passed > (5 * cDbHbInterval) && time_passed > (10 * ctimeOutValue)) { jam(); systemErrorLab(signal, __LINE__); }//if break; } case CS_COMMIT_SENT: jam(); /*------------------------------------------------------------------*/ /* WE HAVE SENT COMMIT TO A NUMBER OF NODES. WE ARE CURRENTLY */ /* WAITING FOR THEIR REPLY. WITH NODE RECOVERY SUPPORTED WE */ /* WILL CHECK FOR CRASHED NODES AND RESEND THE COMMIT SIGNAL */ /* TO THOSE NODES THAT HAVE MISSED THE COMMIT SIGNAL DUE TO */ /* A NODE FAILURE. */ /*------------------------------------------------------------------*/ tabortInd = ZCOMMIT_SETUP; setupFailData(signal); toCommitHandlingLab(signal); return; case CS_COMPLETE_SENT: jam(); /*--------------------------------------------------------------------*/ /* WE HAVE SENT COMPLETE TO A NUMBER OF NODES. WE ARE CURRENTLY */ /* WAITING FOR THEIR REPLY. WITH NODE RECOVERY SUPPORTED WE */ /* WILL CHECK FOR CRASHED NODES AND RESEND THE COMPLETE SIGNAL */ /* TO THOSE NODES THAT HAVE MISSED THE COMPLETE SIGNAL DUE TO */ /* A NODE FAILURE. */ /*--------------------------------------------------------------------*/ tabortInd = ZCOMMIT_SETUP; setupFailData(signal); toCompleteHandlingLab(signal); return; case CS_ABORTING: jam(); /*------------------------------------------------------------------*/ /* TIME-OUT DURING ABORT. WE NEED TO SEND ABORTED FOR ALL */ /* NODES THAT HAVE FAILED BEFORE SENDING ABORTED. */ /*------------------------------------------------------------------*/ tcConnectptr.i = apiConnectptr.p->firstTcConnect; sendAbortedAfterTimeout(signal, 0); break; case CS_START_SCAN:{ jam(); /* We are waiting for application to continue the transaction. In this particular state we will use the application timeout parameter rather than the shorter Deadlock detection timeout. */ if (c_appl_timeout_value == 0 || (ctcTimer - getApiConTimer(apiConnectptr.i)) <= c_appl_timeout_value) { jam(); return; }//if ScanRecordPtr scanPtr; scanPtr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanPtr, cscanrecFileSize, scanRecord); scanError(signal, scanPtr, ZSCANTIME_OUT_ERROR); break; } case CS_WAIT_ABORT_CONF: jam(); tcConnectptr.i = apiConnectptr.p->currentTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { /*------------------------------------------------------------------*/ // Time-out waiting for ABORTCONF. We will resend the ABORTREQ just in // case. /*------------------------------------------------------------------*/ warningReport(signal, 20); apiConnectptr.p->timeOutCounter++; if (apiConnectptr.p->timeOutCounter > 3) { /*------------------------------------------------------------------*/ // 100 time-outs are not acceptable. We will shoot down the node // not responding. /*------------------------------------------------------------------*/ reportNodeFailed(signal, hostptr.i); }//if apiConnectptr.p->currentReplicaNo++; }//if tcurrentReplicaNo = (Uint8)Z8NIL; toAbortHandlingLab(signal); return; case CS_WAIT_COMMIT_CONF: jam(); CRASH_INSERTION(8053); tcConnectptr.i = apiConnectptr.p->currentTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { /*------------------------------------------------------------------*/ // Time-out waiting for COMMITCONF. We will resend the COMMITREQ just in // case. /*------------------------------------------------------------------*/ warningReport(signal, 21); apiConnectptr.p->timeOutCounter++; if (apiConnectptr.p->timeOutCounter > 3) { /*------------------------------------------------------------------*/ // 100 time-outs are not acceptable. We will shoot down the node // not responding. /*------------------------------------------------------------------*/ reportNodeFailed(signal, hostptr.i); }//if apiConnectptr.p->currentReplicaNo++; }//if tcurrentReplicaNo = (Uint8)Z8NIL; toCommitHandlingLab(signal); return; case CS_WAIT_COMPLETE_CONF: jam(); tcConnectptr.i = apiConnectptr.p->currentTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); hostptr.i = tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { /*------------------------------------------------------------------*/ // Time-out waiting for COMPLETECONF. We will resend the COMPLETEREQ // just in case. /*------------------------------------------------------------------*/ warningReport(signal, 22); apiConnectptr.p->timeOutCounter++; if (apiConnectptr.p->timeOutCounter > 100) { /*------------------------------------------------------------------*/ // 100 time-outs are not acceptable. We will shoot down the node // not responding. /*------------------------------------------------------------------*/ reportNodeFailed(signal, hostptr.i); }//if apiConnectptr.p->currentReplicaNo++; }//if tcurrentReplicaNo = (Uint8)Z8NIL; toCompleteHandlingLab(signal); return; case CS_FAIL_PREPARED: jam(); case CS_FAIL_COMMITTING: jam(); case CS_FAIL_COMMITTED: jam(); case CS_REC_PREPARING: jam(); case CS_START_PREPARING: jam(); case CS_PREPARED: jam(); case CS_RESTART: jam(); case CS_FAIL_ABORTED: jam(); case CS_DISCONNECTED: jam(); default: jam(); /*------------------------------------------------------------------*/ /* AN IMPOSSIBLE STATE IS SET. CRASH THE SYSTEM. */ /*------------------------------------------------------------------*/ DEBUG("State = " << apiConnectptr.p->apiConnectstate); systemErrorLab(signal, __LINE__); return; }//switch return; }//Dbtc::timeOutFoundLab() void Dbtc::sendAbortedAfterTimeout(Signal* signal, int Tcheck) { ApiConnectRecord * transP = apiConnectptr.p; if(transP->abortState == AS_IDLE){ jam(); warningEvent("TC: %d: %d state=%d abort==IDLE place: %d fop=%d t: %d", __LINE__, apiConnectptr.i, transP->apiConnectstate, c_apiConTimer_line[apiConnectptr.i], transP->firstTcConnect, c_apiConTimer[apiConnectptr.i] ); ndbout_c("TC: %d: %d state=%d abort==IDLE place: %d fop=%d t: %d", __LINE__, apiConnectptr.i, transP->apiConnectstate, c_apiConTimer_line[apiConnectptr.i], transP->firstTcConnect, c_apiConTimer[apiConnectptr.i] ); ndbrequire(false); setApiConTimer(apiConnectptr.i, 0, __LINE__); return; } bool found = false; OperationState tmp[16]; Uint32 TloopCount = 0; do { jam(); if (tcConnectptr.i == RNIL) { jam(); #ifdef VM_TRACE ndbout_c("found: %d Tcheck: %d apiConnectptr.p->counter: %d", found, Tcheck, apiConnectptr.p->counter); #endif if (found || apiConnectptr.p->counter) { jam(); /** * We sent atleast one ABORT/ABORTED * or ZABORT_TIMEOUT_BREAK is in job buffer * wait for reception... */ return; } if (Tcheck == 1) { jam(); releaseAbortResources(signal); return; } if (Tcheck == 0) { jam(); /*------------------------------------------------------------------ * All nodes had already reported ABORTED for all tcConnect records. * Crash since it is an error situation that we then received a * time-out. *------------------------------------------------------------------*/ char buf[96]; buf[0] = 0; char buf2[96]; BaseString::snprintf(buf, sizeof(buf), "TC %d: %d counter: %d ops:", __LINE__, apiConnectptr.i, apiConnectptr.p->counter); for(Uint32 i = 0; i= 1024) { jam(); /*------------------------------------------------------------------*/ // Insert a real-time break for large transactions to avoid blowing // away the job buffer. /*------------------------------------------------------------------*/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); apiConnectptr.p->counter++; signal->theData[0] = TcContinueB::ZABORT_TIMEOUT_BREAK; signal->theData[1] = tcConnectptr.i; signal->theData[2] = apiConnectptr.i; if (ERROR_INSERTED(8050)) { ndbout_c("sending ZABORT_TIMEOUT_BREAK delayed (%d %d)", Tcheck, apiConnectptr.p->counter); sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 2000, 3); } else { sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); } return; }//if ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); if(TloopCount < 16){ jam(); tmp[TloopCount-1] = tcConnectptr.p->tcConnectstate; } if (tcConnectptr.p->tcConnectstate == OS_ABORT_SENT) { jam(); /*------------------------------------------------------------------*/ // We have sent an ABORT signal to this node but not yet received any // reply. We have to send an ABORTED signal on our own in some cases. // If the node is declared as up and running and still do not respond // in time to the ABORT signal we will declare it as dead. /*------------------------------------------------------------------*/ UintR Ti = 0; arrGuard(tcConnectptr.p->noOfNodes, MAX_REPLICAS+1); for (Ti = 0; Ti < tcConnectptr.p->noOfNodes; Ti++) { jam(); if (tcConnectptr.p->tcNodedata[Ti] != 0) { TloopCount += 31; found = true; hostptr.i = tcConnectptr.p->tcNodedata[Ti]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { jam(); /*--------------------------------------------------------------- * A backup replica has not sent ABORTED. * Could be that a node before him has crashed. * Send an ABORT signal specifically to this node. * We will not send to any more nodes after this * to avoid race problems. * To also ensure that we use this message also as a heartbeat * we will move this node to the primary replica seat. * The primary replica and any failed node after it will * be removed from the node list. Update also number of nodes. * Finally break the loop to ensure we don't mess * things up by executing another loop. * We also update the timer to ensure we don't get time-out * too early. *--------------------------------------------------------------*/ BlockReference TBRef = calcLqhBlockRef(hostptr.i); signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; signal->theData[2] = apiConnectptr.p->transid[0]; signal->theData[3] = apiConnectptr.p->transid[1]; sendSignal(TBRef, GSN_ABORT, signal, 4, JBB); setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); break; } else { jam(); /*-------------------------------------------------------------- * The node we are waiting for is dead. We will send ABORTED to * ourselves vicarious for the failed node. *--------------------------------------------------------------*/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); signal->theData[0] = tcConnectptr.i; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; signal->theData[3] = hostptr.i; signal->theData[4] = ZFALSE; sendSignal(cownref, GSN_ABORTED, signal, 5, JBB); }//if }//if }//for }//if tcConnectptr.i = tcConnectptr.p->nextTcConnect; } while (1); }//Dbtc::sendAbortedAfterTimeout() void Dbtc::reportNodeFailed(Signal* signal, Uint32 nodeId) { DisconnectRep * const rep = (DisconnectRep *)&signal->theData[0]; rep->nodeId = nodeId; rep->err = DisconnectRep::TcReportNodeFailed; sendSignal(QMGR_REF, GSN_DISCONNECT_REP, signal, DisconnectRep::SignalLength, JBB); }//Dbtc::reportNodeFailed() /*-------------------------------------------------*/ /* Timeout-loop for scanned fragments. */ /*-------------------------------------------------*/ void Dbtc::timeOutLoopStartFragLab(Signal* signal, Uint32 TscanConPtr) { ScanFragRecPtr timeOutPtr[8]; UintR tfragTimer[8]; UintR texpiredTime[8]; UintR TloopCount = 0; Uint32 TtcTimer = ctcTimer; while ((TscanConPtr + 8) < cscanFragrecFileSize) { jam(); timeOutPtr[0].i = TscanConPtr + 0; timeOutPtr[1].i = TscanConPtr + 1; timeOutPtr[2].i = TscanConPtr + 2; timeOutPtr[3].i = TscanConPtr + 3; timeOutPtr[4].i = TscanConPtr + 4; timeOutPtr[5].i = TscanConPtr + 5; timeOutPtr[6].i = TscanConPtr + 6; timeOutPtr[7].i = TscanConPtr + 7; c_scan_frag_pool.getPtrForce(timeOutPtr[0]); c_scan_frag_pool.getPtrForce(timeOutPtr[1]); c_scan_frag_pool.getPtrForce(timeOutPtr[2]); c_scan_frag_pool.getPtrForce(timeOutPtr[3]); c_scan_frag_pool.getPtrForce(timeOutPtr[4]); c_scan_frag_pool.getPtrForce(timeOutPtr[5]); c_scan_frag_pool.getPtrForce(timeOutPtr[6]); c_scan_frag_pool.getPtrForce(timeOutPtr[7]); tfragTimer[0] = timeOutPtr[0].p->scanFragTimer; tfragTimer[1] = timeOutPtr[1].p->scanFragTimer; tfragTimer[2] = timeOutPtr[2].p->scanFragTimer; tfragTimer[3] = timeOutPtr[3].p->scanFragTimer; tfragTimer[4] = timeOutPtr[4].p->scanFragTimer; tfragTimer[5] = timeOutPtr[5].p->scanFragTimer; tfragTimer[6] = timeOutPtr[6].p->scanFragTimer; tfragTimer[7] = timeOutPtr[7].p->scanFragTimer; texpiredTime[0] = TtcTimer - tfragTimer[0]; texpiredTime[1] = TtcTimer - tfragTimer[1]; texpiredTime[2] = TtcTimer - tfragTimer[2]; texpiredTime[3] = TtcTimer - tfragTimer[3]; texpiredTime[4] = TtcTimer - tfragTimer[4]; texpiredTime[5] = TtcTimer - tfragTimer[5]; texpiredTime[6] = TtcTimer - tfragTimer[6]; texpiredTime[7] = TtcTimer - tfragTimer[7]; for (Uint32 Ti = 0; Ti < 8; Ti++) { jam(); if (tfragTimer[Ti] != 0) { if (texpiredTime[Ti] > ctimeOutValue) { jam(); DEBUG("Fragment timeout found:"<< " ctimeOutValue=" <theData[3]<<", "<theData[4]<<")"); return; }//if // Update timer on ScanFragRec if (scanFragptr.p->scanFragTimer != 0){ updateBuddyTimer(apiConnectptr); scanFragptr.p->startFragTimer(ctcTimer); } else { ndbassert(false); DEBUG("SCAN_HBREP when scanFragTimer was turned off"); } }//execSCAN_HBREP() /*--------------------------------------------------------------------------*/ /* Timeout has occured on a fragment which means a scan has timed out. */ /* If this is true we have an error in LQH/ACC. */ /*--------------------------------------------------------------------------*/ void Dbtc::timeOutFoundFragLab(Signal* signal, UintR TscanConPtr) { ScanFragRecPtr ptr; c_scan_frag_pool.getPtr(ptr, TscanConPtr); DEBUG(TscanConPtr << " timeOutFoundFragLab: scanFragState = "<< ptr.p->scanFragState); const Uint32 time_out_param= ctimeOutValue; const Uint32 old_time_out_param= c_abortRec.oldTimeOutValue; if (unlikely(time_out_param != old_time_out_param && getNodeState().getSingleUserMode())) { jam(); ScanRecordPtr scanptr; scanptr.i = ptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); ApiConnectRecordPtr TlocalApiConnectptr; TlocalApiConnectptr.i = scanptr.p->scanApiRec; ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord); if (refToNode(TlocalApiConnectptr.p->ndbapiBlockref) == getNodeState().getSingleUserApi()) { jam(); Uint32 val = ctcTimer - ptr.p->scanFragTimer; if (val <= old_time_out_param) { jam(); goto next; } } } /*-------------------------------------------------------------------------*/ // The scan fragment has expired its timeout. Check its state to decide // what to do. /*-------------------------------------------------------------------------*/ switch (ptr.p->scanFragState) { case ScanFragRec::WAIT_GET_PRIMCONF: jam(); ndbrequire(false); break; case ScanFragRec::LQH_ACTIVE:{ jam(); /** * The LQH expired it's timeout, try to close it */ Uint32 nodeId = refToNode(ptr.p->lqhBlockref); Uint32 connectCount = getNodeInfo(nodeId).m_connectCount; ScanRecordPtr scanptr; scanptr.i = ptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); if(connectCount != ptr.p->m_connectCount){ jam(); /** * The node has died */ ptr.p->scanFragState = ScanFragRec::COMPLETED; ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(ptr); ptr.p->stopFragTimer(); } scanError(signal, scanptr, ZSCAN_FRAG_LQH_ERROR); break; } case ScanFragRec::DELIVERED: jam(); case ScanFragRec::IDLE: jam(); case ScanFragRec::QUEUED_FOR_DELIVERY: jam(); /*----------------------------------------------------------------------- * Should never occur. We will simply report set the timer to zero and * continue. In a debug version we should crash here but not in a release * version. In a release version we will simply set the time-out to zero. *-----------------------------------------------------------------------*/ #ifdef VM_TRACE systemErrorLab(signal, __LINE__); #endif scanFragptr.p->stopFragTimer(); break; default: jam(); /*----------------------------------------------------------------------- * Non-existent state. Crash. *-----------------------------------------------------------------------*/ systemErrorLab(signal, __LINE__); break; }//switch next: signal->theData[0] = TcContinueB::ZCONTINUE_TIME_OUT_FRAG_CONTROL; signal->theData[1] = TscanConPtr + 1; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//timeOutFoundFragLab() /* 4.3.16 GCP_NOMORETRANS ---------------------- */ /***************************************************************************** * G C P _ N O M O R E T R A N S * * WHEN DBTC RECEIVES SIGNAL GCP_NOMORETRANS A CHECK IS DONE TO FIND OUT IF * THERE ARE ANY GLOBAL CHECKPOINTS GOING ON - CFIRSTGCP /= RNIL. DBTC THEN * SEARCHES THE GCP_RECORD FILE TO FIND OUT IF THERE ARE ANY TRANSACTIONS NOT * CONCLUDED WITH THIS SPECIFIC CHECKPOINT - GCP_PTR:GCP_ID = TCHECK_GCP_ID. * FOR EACH TRANSACTION WHERE API_CONNECTSTATE EQUALS PREPARED, COMMITTING, * COMMITTED OR COMPLETING SIGNAL CONTINUEB IS SENT WITH A DELAY OF 100 MS, * THE COUNTER GCP_PTR:OUTSTANDINGAPI IS INCREASED. WHEN CONTINUEB IS RECEIVED * THE COUNTER IS DECREASED AND A CHECK IS DONE TO FIND OUT IF ALL * TRANSACTIONS ARE CONCLUDED. IF SO, SIGNAL GCP_TCFINISHED IS SENT. *****************************************************************************/ void Dbtc::execGCP_NOMORETRANS(Signal* signal) { jamEntry(); c_gcp_ref = signal->theData[0]; tcheckGcpId = signal->theData[1]; if (cfirstgcp != RNIL) { jam(); /* A GLOBAL CHECKPOINT IS GOING ON */ gcpPtr.i = cfirstgcp; /* SET POINTER TO FIRST GCP IN QUEUE*/ ptrCheckGuard(gcpPtr, cgcpFilesize, gcpRecord); if (gcpPtr.p->gcpId == tcheckGcpId) { jam(); if (gcpPtr.p->firstApiConnect != RNIL) { jam(); gcpPtr.p->gcpNomoretransRec = ZTRUE; } else { jam(); gcpTcfinished(signal); unlinkGcp(signal); }//if } else { jam(); /*------------------------------------------------------------*/ /* IF IT IS NOT THE FIRST THEN THERE SHOULD BE NO */ /* RECORD FOR THIS GLOBAL CHECKPOINT. WE ALWAYS REMOVE */ /* THE GLOBAL CHECKPOINTS IN ORDER. */ /*------------------------------------------------------------*/ gcpTcfinished(signal); }//if } else { jam(); gcpTcfinished(signal); }//if return; }//Dbtc::execGCP_NOMORETRANS() /*****************************************************************************/ /* */ /* TAKE OVER MODULE */ /* */ /*****************************************************************************/ /* */ /* THIS PART OF TC TAKES OVER THE COMMIT/ABORT OF TRANSACTIONS WHERE THE */ /* NODE ACTING AS TC HAVE FAILED. IT STARTS BY QUERYING ALL NODES ABOUT */ /* ANY OPERATIONS PARTICIPATING IN A TRANSACTION WHERE THE TC NODE HAVE */ /* FAILED. */ /* */ /* AFTER RECEIVING INFORMATION FROM ALL NODES ABOUT OPERATION STATUS THIS */ /* CODE WILL ENSURE THAT ALL AFFECTED TRANSACTIONS ARE PROPERLY ABORTED OR*/ /* COMMITTED. THE ORIGINATING APPLICATION NODE WILL ALSO BE CONTACTED. */ /* IF THE ORIGINATING APPLICATION ALSO FAILED THEN THERE IS CURRENTLY NO */ /* WAY TO FIND OUT WHETHER A TRANSACTION WAS PERFORMED OR NOT. */ /*****************************************************************************/ void Dbtc::execNODE_FAILREP(Signal* signal) { jamEntry(); NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0]; cfailure_nr = nodeFail->failNo; const Uint32 tnoOfNodes = nodeFail->noOfNodes; const Uint32 tnewMasterId = nodeFail->masterNodeId; arrGuard(tnoOfNodes, MAX_NDB_NODES); Uint32 i; int index = 0; for (i = 1; i< MAX_NDB_NODES; i++) { if(NodeBitmask::get(nodeFail->theNodes, i)) { cdata[index] = i; index++; }//if }//for cmasterNodeId = tnewMasterId; tcNodeFailptr.i = 0; ptrAss(tcNodeFailptr, tcFailRecord); for (i = 0; i < tnoOfNodes; i++) { jam(); hostptr.i = cdata[i]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); /*------------------------------------------------------------*/ /* SET STATUS OF THE FAILED NODE TO DEAD SINCE IT HAS */ /* FAILED. */ /*------------------------------------------------------------*/ hostptr.p->hostStatus = HS_DEAD; hostptr.p->m_nf_bits = HostRecord::NF_NODE_FAIL_BITS; c_alive_nodes.clear(hostptr.i); if (tcNodeFailptr.p->failStatus == FS_LISTENING) { jam(); /*------------------------------------------------------------*/ /* THE CURRENT TAKE OVER CAN BE AFFECTED BY THIS NODE */ /* FAILURE. */ /*------------------------------------------------------------*/ if (hostptr.p->lqhTransStatus == LTS_ACTIVE) { jam(); /*------------------------------------------------------------*/ /* WE WERE WAITING FOR THE FAILED NODE IN THE TAKE OVER */ /* PROTOCOL FOR TC. */ /*------------------------------------------------------------*/ signal->theData[0] = TcContinueB::ZNODE_TAKE_OVER_COMPLETED; signal->theData[1] = hostptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if }//if if (getOwnNodeId() != tnewMasterId) { jam(); /** * Only master does takeover currently */ hostptr.p->m_nf_bits &= ~HostRecord::NF_TAKEOVER; } else { jam(); signal->theData[0] = hostptr.i; sendSignal(cownref, GSN_TAKE_OVERTCREQ, signal, 1, JBB); } checkScanActiveInFailedLqh(signal, 0, hostptr.i); checkWaitDropTabFailedLqh(signal, hostptr.i, 0); // nodeid, tableid nodeFailCheckTransactions(signal, 0, hostptr.i); } }//Dbtc::execNODE_FAILREP() void Dbtc::checkNodeFailComplete(Signal* signal, Uint32 failedNodeId, Uint32 bit) { hostptr.i = failedNodeId; ptrCheckGuard(hostptr, chostFilesize, hostRecord); hostptr.p->m_nf_bits &= ~bit; if (hostptr.p->m_nf_bits == 0) { NFCompleteRep * const nfRep = (NFCompleteRep *)&signal->theData[0]; nfRep->blockNo = DBTC; nfRep->nodeId = cownNodeid; nfRep->failedNodeId = hostptr.i; sendSignal(cdihblockref, GSN_NF_COMPLETEREP, signal, NFCompleteRep::SignalLength, JBB); } } void Dbtc::checkScanActiveInFailedLqh(Signal* signal, Uint32 scanPtrI, Uint32 failedNodeId){ ScanRecordPtr scanptr; for (scanptr.i = scanPtrI; scanptr.i < cscanrecFileSize; scanptr.i++) { jam(); ptrAss(scanptr, scanRecord); bool found = false; if (scanptr.p->scanState != ScanRecord::IDLE){ jam(); ScanFragRecPtr ptr; ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); for(run.first(ptr); !ptr.isNull(); ){ jam(); ScanFragRecPtr curr = ptr; run.next(ptr); if (curr.p->scanFragState == ScanFragRec::LQH_ACTIVE && refToNode(curr.p->lqhBlockref) == failedNodeId){ jam(); run.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); found = true; } } ScanFragList deliv(c_scan_frag_pool, scanptr.p->m_delivered_scan_frags); for(deliv.first(ptr); !ptr.isNull(); deliv.next(ptr)) { jam(); if (refToNode(ptr.p->lqhBlockref) == failedNodeId) { jam(); found = true; break; } } } if(found){ jam(); scanError(signal, scanptr, ZSCAN_LQH_ERROR); } // Send CONTINUEB to continue later signal->theData[0] = TcContinueB::ZCHECK_SCAN_ACTIVE_FAILED_LQH; signal->theData[1] = scanptr.i + 1; // Check next scanptr signal->theData[2] = failedNodeId; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); return; }//for checkNodeFailComplete(signal, failedNodeId, HostRecord::NF_CHECK_SCAN); } void Dbtc::nodeFailCheckTransactions(Signal* signal, Uint32 transPtrI, Uint32 failedNodeId) { jam(); Ptr transPtr; Uint32 TtcTimer = ctcTimer; Uint32 TapplTimeout = c_appl_timeout_value; for (transPtr.i = transPtrI; transPtr.i < capiConnectFilesize; transPtr.i++) { ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord); if (transPtr.p->m_transaction_nodes.get(failedNodeId)) { jam(); // Force timeout regardless of state c_appl_timeout_value = 1; setApiConTimer(transPtr.i, TtcTimer - 2, __LINE__); timeOutFoundLab(signal, transPtr.i, ZNODEFAIL_BEFORE_COMMIT); c_appl_timeout_value = TapplTimeout; } // Send CONTINUEB to continue later signal->theData[0] = TcContinueB::ZNF_CHECK_TRANSACTIONS; signal->theData[1] = transPtr.i + 1; // Check next signal->theData[2] = failedNodeId; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); return; } checkNodeFailComplete(signal, failedNodeId, HostRecord::NF_CHECK_TRANSACTION); } void Dbtc::checkScanFragList(Signal* signal, Uint32 failedNodeId, ScanRecord * scanP, ScanFragList::Head & head){ DEBUG("checkScanActiveInFailedLqh: scanFragError"); } void Dbtc::execTAKE_OVERTCCONF(Signal* signal) { jamEntry(); tfailedNodeId = signal->theData[0]; hostptr.i = tfailedNodeId; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (signal->getSendersBlockRef() != reference()) { jam(); return; } checkNodeFailComplete(signal, hostptr.i, HostRecord::NF_TAKEOVER); }//Dbtc::execTAKE_OVERTCCONF() void Dbtc::execTAKE_OVERTCREQ(Signal* signal) { jamEntry(); tfailedNodeId = signal->theData[0]; tcNodeFailptr.i = 0; ptrAss(tcNodeFailptr, tcFailRecord); if (tcNodeFailptr.p->failStatus != FS_IDLE) { jam(); /*------------------------------------------------------------*/ /* WE CAN CURRENTLY ONLY HANDLE ONE TAKE OVER AT A TIME */ /*------------------------------------------------------------*/ /* IF MORE THAN ONE TAKE OVER IS REQUESTED WE WILL */ /* QUEUE THE TAKE OVER AND START IT AS SOON AS THE */ /* PREVIOUS ARE COMPLETED. */ /*------------------------------------------------------------*/ arrGuard(tcNodeFailptr.p->queueIndex, MAX_NDB_NODES); tcNodeFailptr.p->queueList[tcNodeFailptr.p->queueIndex] = tfailedNodeId; tcNodeFailptr.p->queueIndex = tcNodeFailptr.p->queueIndex + 1; return; }//if startTakeOverLab(signal); }//Dbtc::execTAKE_OVERTCREQ() /*------------------------------------------------------------*/ /* INITIALISE THE HASH TABLES FOR STORING TRANSACTIONS */ /* AND OPERATIONS DURING TC TAKE OVER. */ /*------------------------------------------------------------*/ void Dbtc::startTakeOverLab(Signal* signal) { for (tindex = 0; tindex <= 511; tindex++) { ctransidFailHash[tindex] = RNIL; }//for for (tindex = 0; tindex <= 1023; tindex++) { ctcConnectFailHash[tindex] = RNIL; }//for tcNodeFailptr.p->failStatus = FS_LISTENING; tcNodeFailptr.p->takeOverNode = tfailedNodeId; for (hostptr.i = 1; hostptr.i < MAX_NDB_NODES; hostptr.i++) { jam(); ptrAss(hostptr, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { jam(); tblockref = calcLqhBlockRef(hostptr.i); hostptr.p->lqhTransStatus = LTS_ACTIVE; signal->theData[0] = tcNodeFailptr.i; signal->theData[1] = cownref; signal->theData[2] = tfailedNodeId; sendSignal(tblockref, GSN_LQH_TRANSREQ, signal, 3, JBB); }//if }//for }//Dbtc::startTakeOverLab() /*------------------------------------------------------------*/ /* A REPORT OF AN OPERATION WHERE TC FAILED HAS ARRIVED.*/ /*------------------------------------------------------------*/ void Dbtc::execLQH_TRANSCONF(Signal* signal) { jamEntry(); LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0]; tcNodeFailptr.i = lqhTransConf->tcRef; ptrCheckGuard(tcNodeFailptr, 1, tcFailRecord); tnodeid = lqhTransConf->lqhNodeId; ttransStatus = (LqhTransConf::OperationStatus)lqhTransConf->operationStatus; ttransid1 = lqhTransConf->transId1; ttransid2 = lqhTransConf->transId2; ttcOprec = lqhTransConf->oldTcOpRec; treqinfo = lqhTransConf->requestInfo; tgci = lqhTransConf->gci; cnodes[0] = lqhTransConf->nextNodeId1; cnodes[1] = lqhTransConf->nextNodeId2; cnodes[2] = lqhTransConf->nextNodeId3; const Uint32 ref = tapplRef = lqhTransConf->apiRef; tapplOprec = lqhTransConf->apiOpRec; const Uint32 tableId = lqhTransConf->tableId; if (ttransStatus == LqhTransConf::LastTransConf){ jam(); /*------------------------------------------------------------*/ /* A NODE HAS REPORTED COMPLETION OF TAKE OVER REPORTING*/ /*------------------------------------------------------------*/ nodeTakeOverCompletedLab(signal); return; }//if if (ttransStatus == LqhTransConf::Marker){ jam(); treqinfo = 0; LqhTransConf::setMarkerFlag(treqinfo, 1); } else { TableRecordPtr tabPtr; tabPtr.i = tableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); switch((DictTabInfo::TableType)tabPtr.p->tableType){ case DictTabInfo::SystemTable: case DictTabInfo::UserTable: break; default: tapplRef = 0; tapplOprec = 0; } } findApiConnectFail(signal); if(apiConnectptr.p->ndbapiBlockref == 0 && tapplRef != 0){ apiConnectptr.p->ndbapiBlockref = ref; apiConnectptr.p->ndbapiConnect = tapplOprec; } if (ttransStatus != LqhTransConf::Marker){ jam(); findTcConnectFail(signal); } }//Dbtc::execLQH_TRANSCONF() /*------------------------------------------------------------*/ /* A NODE HAS REPORTED COMPLETION OF TAKE OVER REPORTING*/ /*------------------------------------------------------------*/ void Dbtc::nodeTakeOverCompletedLab(Signal* signal) { Uint32 guard0; hostptr.i = tnodeid; ptrCheckGuard(hostptr, chostFilesize, hostRecord); hostptr.p->lqhTransStatus = LTS_IDLE; for (hostptr.i = 1; hostptr.i < MAX_NDB_NODES; hostptr.i++) { jam(); ptrAss(hostptr, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { if (hostptr.p->lqhTransStatus == LTS_ACTIVE) { jam(); /*------------------------------------------------------------*/ /* NOT ALL NODES ARE COMPLETED WITH REPORTING IN THE */ /* TAKE OVER. */ /*------------------------------------------------------------*/ return; }//if }//if }//for /*------------------------------------------------------------*/ /* ALL NODES HAVE REPORTED ON THE STATUS OF THE VARIOUS */ /* OPERATIONS THAT WAS CONTROLLED BY THE FAILED TC. WE */ /* ARE NOW IN A POSITION TO COMPLETE ALL OF THOSE */ /* TRANSACTIONS EITHER IN A SUCCESSFUL WAY OR IN AN */ /* UNSUCCESSFUL WAY. WE WILL ALSO REPORT THIS CONCLUSION*/ /* TO THE APPLICATION IF THAT IS STILL ALIVE. */ /*------------------------------------------------------------*/ tcNodeFailptr.p->currentHashIndexTakeOver = 0; tcNodeFailptr.p->completedTakeOver = 0; tcNodeFailptr.p->failStatus = FS_COMPLETING; guard0 = cnoParallelTakeOver - 1; /*------------------------------------------------------------*/ /* WE WILL COMPLETE THE TRANSACTIONS BY STARTING A */ /* NUMBER OF PARALLEL ACTIVITIES. EACH ACTIVITY WILL */ /* COMPLETE ONE TRANSACTION AT A TIME AND IN THAT */ /* TRANSACTION IT WILL COMPLETE ONE OPERATION AT A TIME.*/ /* WHEN ALL ACTIVITIES ARE COMPLETED THEN THE TAKE OVER */ /* IS COMPLETED. */ /*------------------------------------------------------------*/ arrGuard(guard0, MAX_NDB_NODES); for (tindex = 0; tindex <= guard0; tindex++) { jam(); tcNodeFailptr.p->takeOverProcState[tindex] = ZTAKE_OVER_ACTIVE; signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER; signal->theData[1] = tcNodeFailptr.i; signal->theData[2] = tindex; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); }//for }//Dbtc::nodeTakeOverCompletedLab() /*------------------------------------------------------------*/ /* COMPLETE A NEW TRANSACTION FROM THE HASH TABLE OF */ /* TRANSACTIONS TO COMPLETE. */ /*------------------------------------------------------------*/ void Dbtc::completeTransAtTakeOverLab(Signal* signal, UintR TtakeOverInd) { jam(); while (tcNodeFailptr.p->currentHashIndexTakeOver < 512){ jam(); apiConnectptr.i = ctransidFailHash[tcNodeFailptr.p->currentHashIndexTakeOver]; if (apiConnectptr.i != RNIL) { jam(); /*------------------------------------------------------------*/ /* WE HAVE FOUND A TRANSACTION THAT NEEDS TO BE */ /* COMPLETED. REMOVE IT FROM THE HASH TABLE SUCH THAT */ /* NOT ANOTHER ACTIVITY ALSO TRIES TO COMPLETE THIS */ /* TRANSACTION. */ /*------------------------------------------------------------*/ ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ctransidFailHash[tcNodeFailptr.p->currentHashIndexTakeOver] = apiConnectptr.p->nextApiConnect; completeTransAtTakeOverDoOne(signal, TtakeOverInd); // One transaction taken care of, return from this function // and wait for the next CONTINUEB to continue processing break; } else { if (tcNodeFailptr.p->currentHashIndexTakeOver < 511){ jam(); tcNodeFailptr.p->currentHashIndexTakeOver++; } else { jam(); completeTransAtTakeOverDoLast(signal, TtakeOverInd); tcNodeFailptr.p->currentHashIndexTakeOver++; }//if }//if }//while }//Dbtc::completeTransAtTakeOverLab() void Dbtc::completeTransAtTakeOverDoLast(Signal* signal, UintR TtakeOverInd) { Uint32 guard0; /*------------------------------------------------------------*/ /* THERE ARE NO MORE TRANSACTIONS TO COMPLETE. THIS */ /* ACTIVITY IS COMPLETED. */ /*------------------------------------------------------------*/ arrGuard(TtakeOverInd, MAX_NDB_NODES); if (tcNodeFailptr.p->takeOverProcState[TtakeOverInd] != ZTAKE_OVER_ACTIVE) { jam(); systemErrorLab(signal, __LINE__); return; }//if tcNodeFailptr.p->takeOverProcState[TtakeOverInd] = ZTAKE_OVER_IDLE; tcNodeFailptr.p->completedTakeOver++; if (tcNodeFailptr.p->completedTakeOver == cnoParallelTakeOver) { jam(); /*------------------------------------------------------------*/ /* WE WERE THE LAST ACTIVITY THAT WAS COMPLETED. WE NEED*/ /* TO REPORT THE COMPLETION OF THE TAKE OVER TO ALL */ /* NODES THAT ARE ALIVE. */ /*------------------------------------------------------------*/ NodeReceiverGroup rg(DBTC, c_alive_nodes); signal->theData[0] = tcNodeFailptr.p->takeOverNode; sendSignal(rg, GSN_TAKE_OVERTCCONF, signal, 1, JBB); if (tcNodeFailptr.p->queueIndex > 0) { jam(); /*------------------------------------------------------------*/ /* THERE ARE MORE NODES TO TAKE OVER. WE NEED TO START */ /* THE TAKE OVER. */ /*------------------------------------------------------------*/ tfailedNodeId = tcNodeFailptr.p->queueList[0]; guard0 = tcNodeFailptr.p->queueIndex - 1; arrGuard(guard0 + 1, MAX_NDB_NODES); for (tindex = 0; tindex <= guard0; tindex++) { jam(); tcNodeFailptr.p->queueList[tindex] = tcNodeFailptr.p->queueList[tindex + 1]; }//for tcNodeFailptr.p->queueIndex--; startTakeOverLab(signal); return; } else { jam(); tcNodeFailptr.p->failStatus = FS_IDLE; }//if }//if return; }//Dbtc::completeTransAtTakeOverDoLast() void Dbtc::completeTransAtTakeOverDoOne(Signal* signal, UintR TtakeOverInd) { apiConnectptr.p->takeOverRec = (Uint8)tcNodeFailptr.i; apiConnectptr.p->takeOverInd = TtakeOverInd; switch (apiConnectptr.p->apiConnectstate) { case CS_FAIL_COMMITTED: jam(); /*------------------------------------------------------------*/ /* ALL PARTS OF THE TRANSACTIONS REPORTED COMMITTED. WE */ /* HAVE THUS COMPLETED THE COMMIT PHASE. WE CAN REPORT */ /* COMMITTED TO THE APPLICATION AND CONTINUE WITH THE */ /* COMPLETE PHASE. */ /*------------------------------------------------------------*/ sendTCKEY_FAILCONF(signal, apiConnectptr.p); tcConnectptr.i = apiConnectptr.p->firstTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentTcConnect = tcConnectptr.i; apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; toCompleteHandlingLab(signal); return; case CS_FAIL_COMMITTING: jam(); /*------------------------------------------------------------*/ /* AT LEAST ONE PART WAS ONLY PREPARED AND AT LEAST ONE */ /* PART WAS COMMITTED. COMPLETE THE COMMIT PHASE FIRST. */ /* THEN CONTINUE AS AFTER COMMITTED. */ /*------------------------------------------------------------*/ tcConnectptr.i = apiConnectptr.p->firstTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentTcConnect = tcConnectptr.i; apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; toCommitHandlingLab(signal); return; case CS_FAIL_ABORTING: case CS_FAIL_PREPARED: jam(); /*------------------------------------------------------------*/ /* WE WILL ABORT THE TRANSACTION IF IT IS IN A PREPARED */ /* STATE IN THIS VERSION. IN LATER VERSIONS WE WILL */ /* HAVE TO ADD CODE FOR HANDLING OF PREPARED-TO-COMMIT */ /* TRANSACTIONS. THESE ARE NOT ALLOWED TO ABORT UNTIL WE*/ /* HAVE HEARD FROM THE TRANSACTION COORDINATOR. */ /* */ /* IT IS POSSIBLE TO COMMIT TRANSACTIONS THAT ARE */ /* PREPARED ACTUALLY. WE WILL LEAVE THIS PROBLEM UNTIL */ /* LATER VERSIONS. */ /*------------------------------------------------------------*/ tcConnectptr.i = apiConnectptr.p->firstTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentTcConnect = tcConnectptr.i; apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; toAbortHandlingLab(signal); return; case CS_FAIL_ABORTED: jam(); sendTCKEY_FAILREF(signal, apiConnectptr.p); signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER; signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec; signal->theData[2] = apiConnectptr.p->takeOverInd; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); releaseTakeOver(signal); break; case CS_FAIL_COMPLETED: jam(); sendTCKEY_FAILCONF(signal, apiConnectptr.p); signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER; signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec; signal->theData[2] = apiConnectptr.p->takeOverInd; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); releaseApiConnectFail(signal); break; default: jam(); systemErrorLab(signal, __LINE__); return; }//switch }//Dbtc::completeTransAtTakeOverDoOne() void Dbtc::sendTCKEY_FAILREF(Signal* signal, const ApiConnectRecord * regApiPtr){ jam(); const Uint32 ref = regApiPtr->ndbapiBlockref; if(ref != 0){ signal->theData[0] = regApiPtr->ndbapiConnect; signal->theData[1] = regApiPtr->transid[0]; signal->theData[2] = regApiPtr->transid[1]; sendSignal(ref, GSN_TCKEY_FAILREF, signal, 3, JBB); } } void Dbtc::sendTCKEY_FAILCONF(Signal* signal, ApiConnectRecord * regApiPtr){ jam(); TcKeyFailConf * const failConf = (TcKeyFailConf *)&signal->theData[0]; const Uint32 ref = regApiPtr->ndbapiBlockref; const Uint32 marker = regApiPtr->commitAckMarker; if(ref != 0){ failConf->apiConnectPtr = regApiPtr->ndbapiConnect | (marker != RNIL); failConf->transId1 = regApiPtr->transid[0]; failConf->transId2 = regApiPtr->transid[1]; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCKEY_FAILCONF, signal, TcKeyFailConf::SignalLength, JBB); } regApiPtr->commitAckMarker = RNIL; } /*------------------------------------------------------------*/ /* THIS PART HANDLES THE ABORT PHASE IN THE CASE OF A */ /* NODE FAILURE BEFORE THE COMMIT DECISION. */ /*------------------------------------------------------------*/ /* ABORT REQUEST SUCCESSFULLY COMPLETED ON TNODEID */ /*------------------------------------------------------------*/ void Dbtc::execABORTCONF(Signal* signal) { UintR compare_transid1, compare_transid2; jamEntry(); tcConnectptr.i = signal->theData[0]; tnodeid = signal->theData[2]; if (ERROR_INSERTED(8045)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_ABORTCONF, signal, 2000, 5); return; }//if if (tcConnectptr.i >= ctcConnectFilesize) { errorReport(signal, 5); return; }//if ptrAss(tcConnectptr, tcConnectRecord); if (tcConnectptr.p->tcConnectstate != OS_WAIT_ABORT_CONF) { warningReport(signal, 16); return; }//if apiConnectptr.i = tcConnectptr.p->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); if (apiConnectptr.p->apiConnectstate != CS_WAIT_ABORT_CONF) { warningReport(signal, 17); return; }//if compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[3]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[4]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 18); return; }//if arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] != tnodeid) { warningReport(signal, 19); return; }//if tcurrentReplicaNo = (Uint8)Z8NIL; tcConnectptr.p->tcConnectstate = OS_ABORTING; toAbortHandlingLab(signal); }//Dbtc::execABORTCONF() void Dbtc::toAbortHandlingLab(Signal* signal) { do { if (tcurrentReplicaNo != (Uint8)Z8NIL) { jam(); arrGuard(tcurrentReplicaNo, MAX_REPLICAS); const LqhTransConf::OperationStatus stat = (LqhTransConf::OperationStatus) tcConnectptr.p->failData[tcurrentReplicaNo]; switch(stat){ case LqhTransConf::InvalidStatus: case LqhTransConf::Aborted: jam(); /*empty*/; break; case LqhTransConf::Prepared: jam(); hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { jam(); tblockref = calcLqhBlockRef(hostptr.i); setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); tcConnectptr.p->tcConnectstate = OS_WAIT_ABORT_CONF; apiConnectptr.p->apiConnectstate = CS_WAIT_ABORT_CONF; apiConnectptr.p->timeOutCounter = 0; signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; signal->theData[2] = apiConnectptr.p->transid[0]; signal->theData[3] = apiConnectptr.p->transid[1]; signal->theData[4] = apiConnectptr.p->tcBlockref; signal->theData[5] = tcConnectptr.p->tcOprec; sendSignal(tblockref, GSN_ABORTREQ, signal, 6, JBB); return; }//if break; default: jam(); systemErrorLab(signal, __LINE__); return; }//switch }//if if (apiConnectptr.p->currentReplicaNo > 0) { jam(); /*------------------------------------------------------------*/ /* THERE IS STILL ANOTHER REPLICA THAT NEEDS TO BE */ /* ABORTED. */ /*------------------------------------------------------------*/ apiConnectptr.p->currentReplicaNo--; tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo; } else { /*------------------------------------------------------------*/ /* THE LAST REPLICA IN THIS OPERATION HAVE COMMITTED. */ /*------------------------------------------------------------*/ tcConnectptr.i = tcConnectptr.p->nextTcConnect; if (tcConnectptr.i == RNIL) { /*------------------------------------------------------------*/ /* WE HAVE COMPLETED THE ABORT PHASE. WE CAN NOW REPORT */ /* THE ABORT STATUS TO THE APPLICATION AND CONTINUE */ /* WITH THE NEXT TRANSACTION. */ /*------------------------------------------------------------*/ if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) { jam(); sendTCKEY_FAILREF(signal, apiConnectptr.p); const Uint32 marker = apiConnectptr.p->commitAckMarker; if(marker != RNIL){ jam(); CommitAckMarkerPtr tmp; tmp.i = marker; tmp.p = m_commitAckMarkerHash.getPtr(tmp.i); m_commitAckMarkerHash.release(tmp); apiConnectptr.p->commitAckMarker = RNIL; } /*------------------------------------------------------------*/ /* WE HAVE COMPLETED THIS TRANSACTION NOW AND CAN */ /* CONTINUE THE PROCESS WITH THE NEXT TRANSACTION. */ /*------------------------------------------------------------*/ signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER; signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec; signal->theData[2] = apiConnectptr.p->takeOverInd; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); releaseTakeOver(signal); } else { jam(); releaseAbortResources(signal); }//if return; }//if apiConnectptr.p->currentTcConnect = tcConnectptr.i; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; }//if } while (1); }//Dbtc::toAbortHandlingLab() /*------------------------------------------------------------*/ /* THIS PART HANDLES THE COMMIT PHASE IN THE CASE OF A */ /* NODE FAILURE IN THE MIDDLE OF THE COMMIT PHASE. */ /*------------------------------------------------------------*/ /* COMMIT REQUEST SUCCESSFULLY COMPLETED ON TNODEID */ /*------------------------------------------------------------*/ void Dbtc::execCOMMITCONF(Signal* signal) { UintR compare_transid1, compare_transid2; jamEntry(); tcConnectptr.i = signal->theData[0]; tnodeid = signal->theData[1]; if (ERROR_INSERTED(8046)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMMITCONF, signal, 2000, 4); return; }//if if (tcConnectptr.i >= ctcConnectFilesize) { errorReport(signal, 4); return; }//if ptrAss(tcConnectptr, tcConnectRecord); if (tcConnectptr.p->tcConnectstate != OS_WAIT_COMMIT_CONF) { warningReport(signal, 8); return; }//if apiConnectptr.i = tcConnectptr.p->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); if (apiConnectptr.p->apiConnectstate != CS_WAIT_COMMIT_CONF) { warningReport(signal, 9); return; }//if compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[2]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[3]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 10); return; }//if arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] != tnodeid) { warningReport(signal, 11); return; }//if if (ERROR_INSERTED(8026)) { jam(); systemErrorLab(signal, __LINE__); }//if tcurrentReplicaNo = (Uint8)Z8NIL; tcConnectptr.p->tcConnectstate = OS_COMMITTED; toCommitHandlingLab(signal); }//Dbtc::execCOMMITCONF() void Dbtc::toCommitHandlingLab(Signal* signal) { do { if (tcurrentReplicaNo != (Uint8)Z8NIL) { jam(); arrGuard(tcurrentReplicaNo, MAX_REPLICAS); switch (tcConnectptr.p->failData[tcurrentReplicaNo]) { case LqhTransConf::InvalidStatus: jam(); /*empty*/; break; case LqhTransConf::Committed: jam(); /*empty*/; break; case LqhTransConf::Prepared: jam(); /*------------------------------------------------------------*/ /* THE NODE WAS PREPARED AND IS WAITING FOR ABORT OR */ /* COMMIT REQUEST FROM TC. */ /*------------------------------------------------------------*/ hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { jam(); tblockref = calcLqhBlockRef(hostptr.i); setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); apiConnectptr.p->apiConnectstate = CS_WAIT_COMMIT_CONF; apiConnectptr.p->timeOutCounter = 0; tcConnectptr.p->tcConnectstate = OS_WAIT_COMMIT_CONF; signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; signal->theData[2] = apiConnectptr.p->globalcheckpointid; signal->theData[3] = apiConnectptr.p->transid[0]; signal->theData[4] = apiConnectptr.p->transid[1]; signal->theData[5] = apiConnectptr.p->tcBlockref; signal->theData[6] = tcConnectptr.p->tcOprec; sendSignal(tblockref, GSN_COMMITREQ, signal, 7, JBB); return; }//if break; default: jam(); systemErrorLab(signal, __LINE__); return; break; }//switch }//if if (apiConnectptr.p->currentReplicaNo > 0) { jam(); /*------------------------------------------------------------*/ /* THERE IS STILL ANOTHER REPLICA THAT NEEDS TO BE */ /* COMMITTED. */ /*------------------------------------------------------------*/ apiConnectptr.p->currentReplicaNo--; tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo; } else { /*------------------------------------------------------------*/ /* THE LAST REPLICA IN THIS OPERATION HAVE COMMITTED. */ /*------------------------------------------------------------*/ tcConnectptr.i = tcConnectptr.p->nextTcConnect; if (tcConnectptr.i == RNIL) { /*------------------------------------------------------------*/ /* WE HAVE COMPLETED THE COMMIT PHASE. WE CAN NOW REPORT*/ /* THE COMMIT STATUS TO THE APPLICATION AND CONTINUE */ /* WITH THE COMPLETE PHASE. */ /*------------------------------------------------------------*/ if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) { jam(); sendTCKEY_FAILCONF(signal, apiConnectptr.p); } else { jam(); sendApiCommit(signal); }//if apiConnectptr.p->currentTcConnect = apiConnectptr.p->firstTcConnect; tcConnectptr.i = apiConnectptr.p->firstTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; apiConnectptr.p->currentReplicaNo = tcurrentReplicaNo; toCompleteHandlingLab(signal); return; }//if apiConnectptr.p->currentTcConnect = tcConnectptr.i; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; }//if } while (1); }//Dbtc::toCommitHandlingLab() /*------------------------------------------------------------*/ /* COMMON PART TO HANDLE COMPLETE PHASE WHEN ANY NODE */ /* HAVE FAILED. */ /*------------------------------------------------------------*/ /* THE NODE WITH TNODEID HAVE COMPLETED THE OPERATION */ /*------------------------------------------------------------*/ void Dbtc::execCOMPLETECONF(Signal* signal) { UintR compare_transid1, compare_transid2; jamEntry(); tcConnectptr.i = signal->theData[0]; tnodeid = signal->theData[1]; if (ERROR_INSERTED(8047)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMPLETECONF, signal, 2000, 4); return; }//if if (tcConnectptr.i >= ctcConnectFilesize) { errorReport(signal, 3); return; }//if ptrAss(tcConnectptr, tcConnectRecord); if (tcConnectptr.p->tcConnectstate != OS_WAIT_COMPLETE_CONF) { warningReport(signal, 12); return; }//if apiConnectptr.i = tcConnectptr.p->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); if (apiConnectptr.p->apiConnectstate != CS_WAIT_COMPLETE_CONF) { warningReport(signal, 13); return; }//if compare_transid1 = apiConnectptr.p->transid[0] ^ signal->theData[2]; compare_transid2 = apiConnectptr.p->transid[1] ^ signal->theData[3]; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 14); return; }//if arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); if (tcConnectptr.p->tcNodedata[apiConnectptr.p->currentReplicaNo] != tnodeid) { warningReport(signal, 15); return; }//if if (ERROR_INSERTED(8028)) { jam(); systemErrorLab(signal, __LINE__); }//if tcConnectptr.p->tcConnectstate = OS_COMPLETED; tcurrentReplicaNo = (Uint8)Z8NIL; toCompleteHandlingLab(signal); }//Dbtc::execCOMPLETECONF() void Dbtc::toCompleteHandlingLab(Signal* signal) { do { if (tcurrentReplicaNo != (Uint8)Z8NIL) { jam(); arrGuard(tcurrentReplicaNo, MAX_REPLICAS); switch (tcConnectptr.p->failData[tcurrentReplicaNo]) { case LqhTransConf::InvalidStatus: jam(); /*empty*/; break; default: jam(); /*------------------------------------------------------------*/ /* THIS NODE DID NOT REPORT ANYTHING FOR THIS OPERATION */ /* IT MUST HAVE FAILED. */ /*------------------------------------------------------------*/ /*------------------------------------------------------------*/ /* SEND COMPLETEREQ TO THE NEXT REPLICA. */ /*------------------------------------------------------------*/ hostptr.i = tcConnectptr.p->tcNodedata[tcurrentReplicaNo]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus == HS_ALIVE) { jam(); tblockref = calcLqhBlockRef(hostptr.i); setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); tcConnectptr.p->tcConnectstate = OS_WAIT_COMPLETE_CONF; apiConnectptr.p->apiConnectstate = CS_WAIT_COMPLETE_CONF; apiConnectptr.p->timeOutCounter = 0; tcConnectptr.p->apiConnect = apiConnectptr.i; signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; signal->theData[2] = apiConnectptr.p->transid[0]; signal->theData[3] = apiConnectptr.p->transid[1]; signal->theData[4] = apiConnectptr.p->tcBlockref; signal->theData[5] = tcConnectptr.p->tcOprec; sendSignal(tblockref, GSN_COMPLETEREQ, signal, 6, JBB); return; }//if break; }//switch }//if if (apiConnectptr.p->currentReplicaNo != 0) { jam(); /*------------------------------------------------------------*/ /* THERE ARE STILL MORE REPLICAS IN THIS OPERATION. WE */ /* NEED TO CONTINUE WITH THOSE REPLICAS. */ /*------------------------------------------------------------*/ apiConnectptr.p->currentReplicaNo--; tcurrentReplicaNo = apiConnectptr.p->currentReplicaNo; } else { tcConnectptr.i = tcConnectptr.p->nextTcConnect; if (tcConnectptr.i == RNIL) { /*------------------------------------------------------------*/ /* WE HAVE COMPLETED THIS TRANSACTION NOW AND CAN */ /* CONTINUE THE PROCESS WITH THE NEXT TRANSACTION. */ /*------------------------------------------------------------*/ if (apiConnectptr.p->takeOverRec != (Uint8)Z8NIL) { jam(); signal->theData[0] = TcContinueB::ZCOMPLETE_TRANS_AT_TAKE_OVER; signal->theData[1] = (UintR)apiConnectptr.p->takeOverRec; signal->theData[2] = apiConnectptr.p->takeOverInd; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); releaseTakeOver(signal); } else { jam(); releaseTransResources(signal); }//if return; }//if /*------------------------------------------------------------*/ /* WE HAVE COMPLETED AN OPERATION AND THERE ARE MORE TO */ /* COMPLETE. TAKE THE NEXT OPERATION AND START WITH THE */ /* FIRST REPLICA SINCE IT IS THE COMPLETE PHASE. */ /*------------------------------------------------------------*/ apiConnectptr.p->currentTcConnect = tcConnectptr.i; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; apiConnectptr.p->currentReplicaNo = tcurrentReplicaNo; }//if } while (1); }//Dbtc::toCompleteHandlingLab() /*------------------------------------------------------------*/ /* */ /* FIND THE API CONNECT RECORD FOR THIS TRANSACTION */ /* DURING TAKE OVER FROM A FAILED TC. IF NONE EXISTS */ /* YET THEN SEIZE A NEW API CONNECT RECORD AND LINK IT */ /* INTO THE HASH TABLE. */ /*------------------------------------------------------------*/ void Dbtc::findApiConnectFail(Signal* signal) { ApiConnectRecordPtr fafPrevApiConnectptr; ApiConnectRecordPtr fafNextApiConnectptr; UintR tfafHashNumber; tfafHashNumber = ttransid1 & 511; fafPrevApiConnectptr.i = RNIL; ptrNull(fafPrevApiConnectptr); arrGuard(tfafHashNumber, 512); fafNextApiConnectptr.i = ctransidFailHash[tfafHashNumber]; ptrCheck(fafNextApiConnectptr, capiConnectFilesize, apiConnectRecord); FAF_LOOP: jam(); if (fafNextApiConnectptr.i == RNIL) { jam(); if (cfirstfreeApiConnectFail == RNIL) { jam(); systemErrorLab(signal, __LINE__); return; }//if seizeApiConnectFail(signal); if (fafPrevApiConnectptr.i == RNIL) { jam(); ctransidFailHash[tfafHashNumber] = apiConnectptr.i; } else { jam(); ptrGuard(fafPrevApiConnectptr); fafPrevApiConnectptr.p->nextApiConnect = apiConnectptr.i; }//if apiConnectptr.p->nextApiConnect = RNIL; initApiConnectFail(signal); } else { jam(); fafPrevApiConnectptr.i = fafNextApiConnectptr.i; fafPrevApiConnectptr.p = fafNextApiConnectptr.p; apiConnectptr.i = fafNextApiConnectptr.i; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); fafNextApiConnectptr.i = apiConnectptr.p->nextApiConnect; ptrCheck(fafNextApiConnectptr, capiConnectFilesize, apiConnectRecord); if ((apiConnectptr.p->transid[1] != ttransid2) || (apiConnectptr.p->transid[0] != ttransid1)) { goto FAF_LOOP; }//if updateApiStateFail(signal); }//if }//Dbtc::findApiConnectFail() /*----------------------------------------------------------*/ /* FIND THE TC CONNECT AND IF NOT FOUND ALLOCATE A NEW */ /*----------------------------------------------------------*/ void Dbtc::findTcConnectFail(Signal* signal) { UintR tftfHashNumber; tftfHashNumber = (ttransid1 ^ ttcOprec) & 1023; tcConnectptr.i = ctcConnectFailHash[tftfHashNumber]; do { if (tcConnectptr.i == RNIL) { jam(); if (cfirstfreeTcConnectFail == RNIL) { jam(); systemErrorLab(signal, __LINE__); return; }//if seizeTcConnectFail(signal); linkTcInConnectionlist(signal); tcConnectptr.p->nextTcFailHash = ctcConnectFailHash[tftfHashNumber]; ctcConnectFailHash[tftfHashNumber] = tcConnectptr.i; initTcConnectFail(signal); return; } else { ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); if (tcConnectptr.p->tcOprec != ttcOprec) { jam(); /* FRAGMENTID = TC_OPREC HERE, LOOP ANOTHER TURN */ tcConnectptr.i = tcConnectptr.p->nextTcFailHash; } else { updateTcStateFail(signal); return; }//if }//if } while (1); }//Dbtc::findTcConnectFail() /*----------------------------------------------------------*/ /* INITIALISE AN API CONNECT FAIL RECORD */ /*----------------------------------------------------------*/ void Dbtc::initApiConnectFail(Signal* signal) { apiConnectptr.p->transid[0] = ttransid1; apiConnectptr.p->transid[1] = ttransid2; apiConnectptr.p->firstTcConnect = RNIL; apiConnectptr.p->currSavePointId = 0; apiConnectptr.p->lastTcConnect = RNIL; tblockref = calcTcBlockRef(tcNodeFailptr.p->takeOverNode); apiConnectptr.p->tcBlockref = tblockref; apiConnectptr.p->ndbapiBlockref = 0; apiConnectptr.p->ndbapiConnect = 0; apiConnectptr.p->buddyPtr = RNIL; apiConnectptr.p->m_transaction_nodes.clear(); apiConnectptr.p->singleUserMode = 0; setApiConTimer(apiConnectptr.i, 0, __LINE__); switch(ttransStatus){ case LqhTransConf::Committed: jam(); apiConnectptr.p->globalcheckpointid = tgci; apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTED; break; case LqhTransConf::Prepared: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_PREPARED; break; case LqhTransConf::Aborted: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTED; break; case LqhTransConf::Marker: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_COMPLETED; break; default: jam(); systemErrorLab(signal, __LINE__); }//if apiConnectptr.p->commitAckMarker = RNIL; if(LqhTransConf::getMarkerFlag(treqinfo)){ jam(); CommitAckMarkerPtr tmp; m_commitAckMarkerHash.seize(tmp); ndbrequire(tmp.i != RNIL); apiConnectptr.p->commitAckMarker = tmp.i; tmp.p->transid1 = ttransid1; tmp.p->transid2 = ttransid2; tmp.p->apiNodeId = refToNode(tapplRef); tmp.p->noOfLqhs = 1; tmp.p->lqhNodeId[0] = tnodeid; tmp.p->apiConnectPtr = apiConnectptr.i; #if defined VM_TRACE || defined ERROR_INSERT { CommitAckMarkerPtr check; ndbrequire(!m_commitAckMarkerHash.find(check, *tmp.p)); } #endif m_commitAckMarkerHash.add(tmp); } }//Dbtc::initApiConnectFail() /*------------------------------------------------------------*/ /* INITIALISE AT TC CONNECT AT TAKE OVER WHEN ALLOCATING*/ /* THE TC CONNECT RECORD. */ /*------------------------------------------------------------*/ void Dbtc::initTcConnectFail(Signal* signal) { tcConnectptr.p->apiConnect = apiConnectptr.i; tcConnectptr.p->tcOprec = ttcOprec; Uint32 treplicaNo = LqhTransConf::getReplicaNo(treqinfo); for (Uint32 i = 0; i < MAX_REPLICAS; i++) { tcConnectptr.p->failData[i] = LqhTransConf::InvalidStatus; }//for tcConnectptr.p->tcNodedata[treplicaNo] = tnodeid; tcConnectptr.p->failData[treplicaNo] = ttransStatus; tcConnectptr.p->lastReplicaNo = LqhTransConf::getLastReplicaNo(treqinfo); tcConnectptr.p->dirtyOp = LqhTransConf::getDirtyFlag(treqinfo); }//Dbtc::initTcConnectFail() /*----------------------------------------------------------*/ /* INITIALISE TC NODE FAIL RECORD. */ /*----------------------------------------------------------*/ void Dbtc::initTcFail(Signal* signal) { tcNodeFailptr.i = 0; ptrAss(tcNodeFailptr, tcFailRecord); tcNodeFailptr.p->queueIndex = 0; tcNodeFailptr.p->failStatus = FS_IDLE; }//Dbtc::initTcFail() /*----------------------------------------------------------*/ /* RELEASE_TAKE_OVER */ /*----------------------------------------------------------*/ void Dbtc::releaseTakeOver(Signal* signal) { TcConnectRecordPtr rtoNextTcConnectptr; rtoNextTcConnectptr.i = apiConnectptr.p->firstTcConnect; do { jam(); tcConnectptr.i = rtoNextTcConnectptr.i; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); rtoNextTcConnectptr.i = tcConnectptr.p->nextTcConnect; releaseTcConnectFail(signal); } while (rtoNextTcConnectptr.i != RNIL); releaseApiConnectFail(signal); }//Dbtc::releaseTakeOver() /*---------------------------------------------------------------------------*/ /* SETUP_FAIL_DATA */ /* SETUP DATA TO REUSE TAKE OVER CODE FOR HANDLING ABORT/COMMIT IN NODE */ /* FAILURE SITUATIONS. */ /*---------------------------------------------------------------------------*/ void Dbtc::setupFailData(Signal* signal) { tcConnectptr.i = apiConnectptr.p->firstTcConnect; do { ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); switch (tcConnectptr.p->tcConnectstate) { case OS_PREPARED: case OS_COMMITTING: jam(); arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS); for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) { jam(); /*------------------------------------------------------------------- * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH. * IN THIS CASE ALL LQH'S ARE PREPARED AND WAITING FOR * COMMIT/ABORT DECISION. *------------------------------------------------------------------*/ tcConnectptr.p->failData[tindex] = LqhTransConf::Prepared; }//for break; case OS_COMMITTED: case OS_COMPLETING: jam(); arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS); for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) { jam(); /*------------------------------------------------------------------- * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH. * IN THIS CASE ALL LQH'S ARE COMMITTED AND WAITING FOR * COMPLETE MESSAGE. *------------------------------------------------------------------*/ tcConnectptr.p->failData[tindex] = LqhTransConf::Committed; }//for break; case OS_COMPLETED: jam(); arrGuard(tcConnectptr.p->lastReplicaNo, MAX_REPLICAS); for (tindex = 0; tindex <= tcConnectptr.p->lastReplicaNo; tindex++) { jam(); /*------------------------------------------------------------------- * KEYDATA IS USED TO KEEP AN INDICATION OF STATE IN LQH. * IN THIS CASE ALL LQH'S ARE COMPLETED. *-------------------------------------------------------------------*/ tcConnectptr.p->failData[tindex] = LqhTransConf::InvalidStatus; }//for break; default: jam(); sendSystemError(signal, __LINE__); break; }//switch if (tabortInd != ZCOMMIT_SETUP) { jam(); for (UintR Ti = 0; Ti <= tcConnectptr.p->lastReplicaNo; Ti++) { hostptr.i = tcConnectptr.p->tcNodedata[Ti]; ptrCheckGuard(hostptr, chostFilesize, hostRecord); if (hostptr.p->hostStatus != HS_ALIVE) { jam(); /*----------------------------------------------------------------- * FAILURE OF ANY INVOLVED NODE ALWAYS INVOKES AN ABORT DECISION. *-----------------------------------------------------------------*/ tabortInd = ZTRUE; }//if }//for }//if tcConnectptr.p->tcConnectstate = OS_TAKE_OVER; tcConnectptr.p->tcOprec = tcConnectptr.i; tcConnectptr.i = tcConnectptr.p->nextTcConnect; } while (tcConnectptr.i != RNIL); apiConnectptr.p->tcBlockref = cownref; apiConnectptr.p->currentTcConnect = apiConnectptr.p->firstTcConnect; tcConnectptr.i = apiConnectptr.p->firstTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->currentReplicaNo = tcConnectptr.p->lastReplicaNo; tcurrentReplicaNo = tcConnectptr.p->lastReplicaNo; }//Dbtc::setupFailData() /*----------------------------------------------------------*/ /* UPDATE THE STATE OF THE API CONNECT FOR THIS PART. */ /*----------------------------------------------------------*/ void Dbtc::updateApiStateFail(Signal* signal) { if(LqhTransConf::getMarkerFlag(treqinfo)){ jam(); const Uint32 marker = apiConnectptr.p->commitAckMarker; if(marker == RNIL){ jam(); CommitAckMarkerPtr tmp; m_commitAckMarkerHash.seize(tmp); ndbrequire(tmp.i != RNIL); apiConnectptr.p->commitAckMarker = tmp.i; tmp.p->transid1 = ttransid1; tmp.p->transid2 = ttransid2; tmp.p->apiNodeId = refToNode(tapplRef); tmp.p->noOfLqhs = 1; tmp.p->lqhNodeId[0] = tnodeid; tmp.p->apiConnectPtr = apiConnectptr.i; #if defined VM_TRACE || defined ERROR_INSERT { CommitAckMarkerPtr check; ndbrequire(!m_commitAckMarkerHash.find(check, *tmp.p)); } #endif m_commitAckMarkerHash.add(tmp); } else { jam(); CommitAckMarkerPtr tmp; tmp.i = marker; tmp.p = m_commitAckMarkerHash.getPtr(marker); const Uint32 noOfLqhs = tmp.p->noOfLqhs; ndbrequire(noOfLqhs < MAX_REPLICAS); tmp.p->lqhNodeId[noOfLqhs] = tnodeid; tmp.p->noOfLqhs = (noOfLqhs + 1); } } switch (ttransStatus) { case LqhTransConf::Committed: jam(); switch (apiConnectptr.p->apiConnectstate) { case CS_FAIL_COMMITTING: case CS_FAIL_COMMITTED: jam(); ndbrequire(tgci == apiConnectptr.p->globalcheckpointid); break; case CS_FAIL_PREPARED: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTING; apiConnectptr.p->globalcheckpointid = tgci; break; case CS_FAIL_COMPLETED: jam(); apiConnectptr.p->globalcheckpointid = tgci; apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTED; break; default: jam(); systemErrorLab(signal, __LINE__); break; }//switch break; case LqhTransConf::Prepared: jam(); switch (apiConnectptr.p->apiConnectstate) { case CS_FAIL_COMMITTED: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_COMMITTING; break; case CS_FAIL_ABORTED: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTING; break; case CS_FAIL_COMMITTING: case CS_FAIL_PREPARED: case CS_FAIL_ABORTING: jam(); /*empty*/; break; default: jam(); systemErrorLab(signal, __LINE__); break; }//switch break; case LqhTransConf::Aborted: jam(); switch (apiConnectptr.p->apiConnectstate) { case CS_FAIL_COMMITTING: case CS_FAIL_COMMITTED: jam(); systemErrorLab(signal, __LINE__); break; case CS_FAIL_PREPARED: jam(); apiConnectptr.p->apiConnectstate = CS_FAIL_ABORTING; break; case CS_FAIL_ABORTING: case CS_FAIL_ABORTED: jam(); /*empty*/; break; default: jam(); systemErrorLab(signal, __LINE__); break; }//switch break; case LqhTransConf::Marker: jam(); break; default: jam(); systemErrorLab(signal, __LINE__); break; }//switch }//Dbtc::updateApiStateFail() /*------------------------------------------------------------*/ /* UPDATE_TC_STATE_FAIL */ /* */ /* WE NEED TO UPDATE THE STATUS OF TC_CONNECT RECORD AND*/ /* WE ALSO NEED TO CHECK THAT THERE IS CONSISTENCY */ /* BETWEEN THE DIFFERENT REPLICAS. */ /*------------------------------------------------------------*/ void Dbtc::updateTcStateFail(Signal* signal) { const Uint8 treplicaNo = LqhTransConf::getReplicaNo(treqinfo); const Uint8 tlastReplicaNo = LqhTransConf::getLastReplicaNo(treqinfo); const Uint8 tdirtyOp = LqhTransConf::getDirtyFlag(treqinfo); TcConnectRecord * regTcPtr = tcConnectptr.p; ndbrequire(regTcPtr->apiConnect == apiConnectptr.i); ndbrequire(regTcPtr->failData[treplicaNo] == LqhTransConf::InvalidStatus); ndbrequire(regTcPtr->lastReplicaNo == tlastReplicaNo); ndbrequire(regTcPtr->dirtyOp == tdirtyOp); regTcPtr->tcNodedata[treplicaNo] = tnodeid; regTcPtr->failData[treplicaNo] = ttransStatus; }//Dbtc::updateTcStateFail() void Dbtc::execTCGETOPSIZEREQ(Signal* signal) { jamEntry(); CRASH_INSERTION(8000); UintR Tuserpointer = signal->theData[0]; /* DBDIH POINTER */ BlockReference Tusersblkref = signal->theData[1];/* DBDIH BLOCK REFERENCE */ signal->theData[0] = Tuserpointer; signal->theData[1] = coperationsize; sendSignal(Tusersblkref, GSN_TCGETOPSIZECONF, signal, 2, JBB); }//Dbtc::execTCGETOPSIZEREQ() void Dbtc::execTC_CLOPSIZEREQ(Signal* signal) { jamEntry(); CRASH_INSERTION(8001); tuserpointer = signal->theData[0]; tusersblkref = signal->theData[1]; /* DBDIH BLOCK REFERENCE */ coperationsize = 0; signal->theData[0] = tuserpointer; sendSignal(tusersblkref, GSN_TC_CLOPSIZECONF, signal, 1, JBB); }//Dbtc::execTC_CLOPSIZEREQ() /* ######################################################################### */ /* ####### ERROR MODULE ####### */ /* ######################################################################### */ void Dbtc::tabStateErrorLab(Signal* signal) { terrorCode = ZSTATE_ERROR; releaseAtErrorLab(signal); }//Dbtc::tabStateErrorLab() void Dbtc::wrongSchemaVersionErrorLab(Signal* signal) { const TcKeyReq * const tcKeyReq = (TcKeyReq *)&signal->theData[0]; TableRecordPtr tabPtr; tabPtr.i = tcKeyReq->tableId; const Uint32 schemVer = tcKeyReq->tableSchemaVersion; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); terrorCode = tabPtr.p->getErrorCode(schemVer); abortErrorLab(signal); }//Dbtc::wrongSchemaVersionErrorLab() void Dbtc::noFreeConnectionErrorLab(Signal* signal) { terrorCode = ZNO_FREE_TC_CONNECTION; abortErrorLab(signal); /* RECORD. OTHERWISE GOTO ERRORHANDLING */ }//Dbtc::noFreeConnectionErrorLab() void Dbtc::aiErrorLab(Signal* signal) { terrorCode = ZLENGTH_ERROR; abortErrorLab(signal); }//Dbtc::aiErrorLab() void Dbtc::seizeAttrbuferrorLab(Signal* signal) { terrorCode = ZGET_ATTRBUF_ERROR; abortErrorLab(signal); }//Dbtc::seizeAttrbuferrorLab() void Dbtc::seizeDatabuferrorLab(Signal* signal) { terrorCode = ZGET_DATAREC_ERROR; releaseAtErrorLab(signal); }//Dbtc::seizeDatabuferrorLab() void Dbtc::releaseAtErrorLab(Signal* signal) { ptrGuard(tcConnectptr); tcConnectptr.p->tcConnectstate = OS_ABORTING; /*-------------------------------------------------------------------------* * A FAILURE OF THIS OPERATION HAS OCCURRED. THIS FAILURE WAS EITHER A * FAULTY PARAMETER OR A RESOURCE THAT WAS NOT AVAILABLE. * WE WILL ABORT THE ENTIRE TRANSACTION SINCE THIS IS THE SAFEST PATH * TO HANDLE THIS PROBLEM. * SINCE WE HAVE NOT YET CONTACTED ANY LQH WE SET NUMBER OF NODES TO ZERO * WE ALSO SET THE STATE TO ABORTING TO INDICATE THAT WE ARE NOT EXPECTING * ANY SIGNALS. *-------------------------------------------------------------------------*/ tcConnectptr.p->noOfNodes = 0; abortErrorLab(signal); }//Dbtc::releaseAtErrorLab() void Dbtc::warningHandlerLab(Signal* signal, int line) { ndbassert(false); }//Dbtc::warningHandlerLab() void Dbtc::systemErrorLab(Signal* signal, int line) { progError(line, NDBD_EXIT_NDBREQUIRE); }//Dbtc::systemErrorLab() /* ######################################################################### * * ####### SCAN MODULE ####### * * ######################################################################### * The application orders a scan of a table. We divide the scan into a scan on each fragment. The scan uses the primary replicas since the scan might be used for an update in a separate transaction. Scans are always done as a separate transaction. Locks from the scan can be overtaken by another transaction. Scans can never lock the entire table. Locks are released immediately after the read has been verified by the application. There is not even an option to leave the locks. The reason is that this would hurt real-time behaviour too much. -# The first step in handling a scan of a table is to receive all signals defining the scan. If failures occur during this step we release all resource and reply with SCAN_TABREF providing the error code. If system load is too high, the request will not be allowed. -# The second step retrieves the number of fragments that exist in the table. It also ensures that the table actually exist. After this, the scan is ready to be parallelised. The idea is that the receiving process (hereafter called delivery process) will start up a number of scan processes. Each of these scan processes will independently scan one fragment at a time. The delivery process object is the scan record and the scan process object is the scan fragment record plus the scan operation record. -# The third step is thus performed in parallel. In the third step each scan process retrieves the primary replica of the fragment it will scan. Then it starts the scan as soon as the load on that node permits. The LQH returns either when it retrieved the maximum number of tuples or when it has retrived at least one tuple and is hindered by a lock to retrieve the next tuple. This is to ensure that a scan process never can be involved in a deadlock situation. When the scan process receives a number of tuples to report to the application it checks the state of the delivery process. Only one delivery at a time is handled by the application. Thus if the delivery process has already sent a number of tuples to the application this set of tuples are queued. When the application requests the next set of tuples it is immediately delivered if any are queued, otherwise it waits for the next scan process that is ready to deliver. ERROR HANDLING As already mentioned it is rather easy to handle errors before the scan processes have started. In this case it is enough to release the resources and send SCAN_TAB_REF. If an error occurs in any of the scan processes then we have to stop all scan processes. We do however only stop the delivery process and ask the api to order us to close the scan. The reason is that we can easily enter into difficult timing problems since the application and this block is out of synch we will thus always start by report the error to the application and wait for a close request. This error report uses the SCAN_TABREF signal with a special error code that the api must check for. CLOSING AN ACTIVE SCAN The application can close a scan for several reasons before it is completed. One reason was mentioned above where an error in a scan process led to a request to close the scan. Another reason could simply be that the application found what it looked for and is thus not interested in the rest of the scan. IT COULD ALSO BE DEPENDENT ON INTERNAL ERRORS IN THE API. When a close scan request is received, all scan processes are stopped and all resources belonging to those scan processes are released. Stopping the scan processes most often includes communication with an LQH where the local scan is controlled. Finally all resources belonging to the scan is released and the SCAN_TABCONF is sent with an indication of that the scan is closed. CLOSING A COMPLETED SCAN When all scan processes are completed then a report is sent to the application which indicates that no more tuples can be fetched. The application will send a close scan and the same action as when closing an active scan is performed. In this case it will of course not find any active scan processes. It will even find all scan processes already released. The reason for requiring the api to close the scan is the same as above. It is to avoid any timing problems due to that the api and this block is out of synch. * ######################################################################## */ void Dbtc::execSCAN_TABREQ(Signal* signal) { const ScanTabReq * const scanTabReq = (ScanTabReq *)&signal->theData[0]; const Uint32 ri = scanTabReq->requestInfo; const Uint32 aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF); const Uint32 keyLen = scanTabReq->attrLenKeyLen >> 16; const Uint32 schemaVersion = scanTabReq->tableSchemaVersion; const Uint32 transid1 = scanTabReq->transId1; const Uint32 transid2 = scanTabReq->transId2; const Uint32 tmpXX = scanTabReq->buddyConPtr; const Uint32 buddyPtr = (tmpXX == 0xFFFFFFFF ? RNIL : tmpXX); Uint32 currSavePointId = 0; Uint32 scanConcurrency = scanTabReq->getParallelism(ri); Uint32 noOprecPerFrag = ScanTabReq::getScanBatch(ri); Uint32 scanParallel = scanConcurrency; Uint32 errCode; ScanRecordPtr scanptr; jamEntry(); SegmentedSectionPtr api_op_ptr; signal->getSection(api_op_ptr, 0); copy(&cdata[0], api_op_ptr); releaseSections(signal); apiConnectptr.i = scanTabReq->apiConnectPtr; tabptr.i = scanTabReq->tableId; if (apiConnectptr.i >= capiConnectFilesize) { jam(); warningHandlerLab(signal, __LINE__); return; }//if ptrAss(apiConnectptr, apiConnectRecord); ApiConnectRecord * transP = apiConnectptr.p; if (transP->apiConnectstate != CS_CONNECTED) { jam(); // could be left over from TCKEYREQ rollback if (transP->apiConnectstate == CS_ABORTING && transP->abortState == AS_IDLE) { jam(); } else if(transP->apiConnectstate == CS_STARTED && transP->firstTcConnect == RNIL){ jam(); // left over from simple/dirty read } else { jam(); jamLine(transP->apiConnectstate); errCode = ZSTATE_ERROR; goto SCAN_TAB_error_no_state_change; } } if(tabptr.i >= ctabrecFilesize) { errCode = ZUNKNOWN_TABLE_ERROR; goto SCAN_TAB_error; } ptrAss(tabptr, tableRecord); if ((aiLength == 0) || (!tabptr.p->checkTable(schemaVersion)) || (scanConcurrency == 0) || (cfirstfreeTcConnect == RNIL) || (cfirstfreeScanrec == RNIL)) { goto SCAN_error_check; } if (buddyPtr != RNIL) { jam(); ApiConnectRecordPtr buddyApiPtr; buddyApiPtr.i = buddyPtr; ptrCheckGuard(buddyApiPtr, capiConnectFilesize, apiConnectRecord); if ((transid1 == buddyApiPtr.p->transid[0]) && (transid2 == buddyApiPtr.p->transid[1])) { jam(); if (buddyApiPtr.p->apiConnectstate == CS_ABORTING) { // transaction has been aborted jam(); errCode = buddyApiPtr.p->returncode; goto SCAN_TAB_error; }//if currSavePointId = buddyApiPtr.p->currSavePointId; buddyApiPtr.p->currSavePointId++; } } if (getNodeState().startLevel == NodeState::SL_SINGLEUSER && getNodeState().getSingleUserApi() != refToNode(apiConnectptr.p->ndbapiBlockref)) { errCode = ZCLUSTER_IN_SINGLEUSER_MODE; goto SCAN_TAB_error; } seizeTcConnect(signal); tcConnectptr.p->apiConnect = apiConnectptr.i; tcConnectptr.p->tcConnectstate = OS_WAIT_SCAN; apiConnectptr.p->lastTcConnect = tcConnectptr.i; seizeCacheRecord(signal); cachePtr.p->keylen = keyLen; cachePtr.p->save1 = 0; cachePtr.p->distributionKey = scanTabReq->distributionKey; cachePtr.p->distributionKeyIndicator= ScanTabReq::getDistributionKeyFlag(ri); scanptr = seizeScanrec(signal); ndbrequire(transP->apiScanRec == RNIL); ndbrequire(scanptr.p->scanApiRec == RNIL); initScanrec(scanptr, scanTabReq, scanParallel, noOprecPerFrag); transP->apiScanRec = scanptr.i; transP->returncode = 0; transP->transid[0] = transid1; transP->transid[1] = transid2; transP->buddyPtr = buddyPtr; // The scan is started transP->apiConnectstate = CS_START_SCAN; transP->currSavePointId = currSavePointId; /********************************************************** * We start the timer on scanRec to be able to discover a * timeout in the API the API now is in charge! ***********************************************************/ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); updateBuddyTimer(apiConnectptr); /*********************************************************** * WE HAVE NOW RECEIVED ALL REFERENCES TO SCAN OBJECTS IN * THE API. WE ARE NOW READY TO RECEIVE THE ATTRIBUTE INFO * IF ANY TO RECEIVE. **********************************************************/ scanptr.p->scanState = ScanRecord::WAIT_AI; if (ERROR_INSERTED(8038)) { /** * Force API_FAILREQ */ DisconnectRep * const rep = (DisconnectRep *)signal->getDataPtrSend(); rep->nodeId = refToNode(apiConnectptr.p->ndbapiBlockref); rep->err = 8038; EXECUTE_DIRECT(CMVMI, GSN_DISCONNECT_REP, signal, 2); CLEAR_ERROR_INSERT_VALUE; } return; SCAN_error_check: if (aiLength == 0) { jam() errCode = ZSCAN_AI_LEN_ERROR; goto SCAN_TAB_error; }//if if (!tabptr.p->checkTable(schemaVersion)){ jam(); errCode = tabptr.p->getErrorCode(schemaVersion); goto SCAN_TAB_error; }//if if (scanConcurrency == 0) { jam(); errCode = ZNO_CONCURRENCY_ERROR; goto SCAN_TAB_error; }//if if (cfirstfreeTcConnect == RNIL) { jam(); errCode = ZNO_FREE_TC_CONNECTION; goto SCAN_TAB_error; }//if ndbrequire(cfirstfreeScanrec == RNIL); jam(); errCode = ZNO_SCANREC_ERROR; goto SCAN_TAB_error; SCAN_TAB_error: jam(); /** * Prepare for up coming ATTRINFO/KEYINFO */ transP->apiConnectstate = CS_ABORTING; transP->abortState = AS_IDLE; transP->transid[0] = transid1; transP->transid[1] = transid2; SCAN_TAB_error_no_state_change: ScanTabRef * ref = (ScanTabRef*)&signal->theData[0]; ref->apiConnectPtr = transP->ndbapiConnect; ref->transId1 = transid1; ref->transId2 = transid2; ref->errorCode = errCode; ref->closeNeeded = 0; sendSignal(transP->ndbapiBlockref, GSN_SCAN_TABREF, signal, ScanTabRef::SignalLength, JBB); return; }//Dbtc::execSCAN_TABREQ() void Dbtc::initScanrec(ScanRecordPtr scanptr, const ScanTabReq * scanTabReq, UintR scanParallel, UintR noOprecPerFrag) { const UintR ri = scanTabReq->requestInfo; scanptr.p->scanTcrec = tcConnectptr.i; scanptr.p->scanApiRec = apiConnectptr.i; scanptr.p->scanAiLength = scanTabReq->attrLenKeyLen & 0xFFFF; scanptr.p->scanKeyLen = scanTabReq->attrLenKeyLen >> 16; scanptr.p->scanTableref = tabptr.i; scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion; scanptr.p->scanParallel = scanParallel; scanptr.p->first_batch_size_rows = scanTabReq->first_batch_size; scanptr.p->batch_byte_size = scanTabReq->batch_byte_size; scanptr.p->batch_size_rows = noOprecPerFrag; Uint32 tmp = 0; ScanFragReq::setLockMode(tmp, ScanTabReq::getLockMode(ri)); ScanFragReq::setHoldLockFlag(tmp, ScanTabReq::getHoldLockFlag(ri)); ScanFragReq::setKeyinfoFlag(tmp, ScanTabReq::getKeyinfoFlag(ri)); ScanFragReq::setReadCommittedFlag(tmp,ScanTabReq::getReadCommittedFlag(ri)); ScanFragReq::setRangeScanFlag(tmp, ScanTabReq::getRangeScanFlag(ri)); ScanFragReq::setDescendingFlag(tmp, ScanTabReq::getDescendingFlag(ri)); ScanFragReq::setTupScanFlag(tmp, ScanTabReq::getTupScanFlag(ri)); ScanFragReq::setAttrLen(tmp, scanTabReq->attrLenKeyLen & 0xFFFF); ScanFragReq::setNoDiskFlag(tmp, ScanTabReq::getNoDiskFlag(ri)); scanptr.p->scanRequestInfo = tmp; scanptr.p->scanStoredProcId = scanTabReq->storedProcId; scanptr.p->scanState = ScanRecord::RUNNING; scanptr.p->m_queued_count = 0; ScanFragList list(c_scan_frag_pool, scanptr.p->m_running_scan_frags); for (Uint32 i = 0; i < scanParallel; i++) { jam(); ScanFragRecPtr ptr; ndbrequire(list.seize(ptr)); ptr.p->scanFragState = ScanFragRec::IDLE; ptr.p->scanRec = scanptr.i; ptr.p->scanFragId = 0; ptr.p->m_apiPtr = cdata[i]; }//for (* (ScanTabReq::getRangeScanFlag(ri) ? &c_counters.c_range_scan_count : &c_counters.c_scan_count))++; }//Dbtc::initScanrec() void Dbtc::scanTabRefLab(Signal* signal, Uint32 errCode) { ScanTabRef * ref = (ScanTabRef*)&signal->theData[0]; ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect; ref->transId1 = apiConnectptr.p->transid[0]; ref->transId2 = apiConnectptr.p->transid[1]; ref->errorCode = errCode; ref->closeNeeded = 0; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABREF, signal, ScanTabRef::SignalLength, JBB); }//Dbtc::scanTabRefLab() /*---------------------------------------------------------------------------*/ /* */ /* RECEPTION OF ATTRINFO FOR SCAN TABLE REQUEST. */ /*---------------------------------------------------------------------------*/ void Dbtc::scanAttrinfoLab(Signal* signal, UintR Tlen) { ScanRecordPtr scanptr; scanptr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); cachePtr.i = apiConnectptr.p->cachePtr; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); CacheRecord * const regCachePtr = cachePtr.p; ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_AI); regCachePtr->currReclenAi = regCachePtr->currReclenAi + Tlen; if (regCachePtr->currReclenAi < scanptr.p->scanAiLength) { if (cfirstfreeAttrbuf == RNIL) { goto scanAttrinfo_attrbuf_error; }//if saveAttrbuf(signal); } else { if (regCachePtr->currReclenAi > scanptr.p->scanAiLength) { goto scanAttrinfo_len_error; } else { /* CURR_RECLEN_AI = SCAN_AI_LENGTH */ if (cfirstfreeAttrbuf == RNIL) { goto scanAttrinfo_attrbuf2_error; }//if saveAttrbuf(signal); /************************************************** * WE HAVE NOW RECEIVED ALL INFORMATION CONCERNING * THIS SCAN. WE ARE READY TO START THE ACTUAL * EXECUTION OF THE SCAN QUERY **************************************************/ diFcountReqLab(signal, scanptr); return; }//if }//if return; scanAttrinfo_attrbuf_error: jam(); abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true); return; scanAttrinfo_attrbuf2_error: jam(); abortScanLab(signal, scanptr, ZGET_ATTRBUF_ERROR, true); return; scanAttrinfo_len_error: jam(); abortScanLab(signal, scanptr, ZLENGTH_ERROR, true); return; }//Dbtc::scanAttrinfoLab() void Dbtc::diFcountReqLab(Signal* signal, ScanRecordPtr scanptr) { /** * Check so that the table is not being dropped */ TableRecordPtr tabPtr; tabPtr.i = scanptr.p->scanTableref; tabPtr.p = &tableRecord[tabPtr.i]; if (tabPtr.p->checkTable(scanptr.p->scanSchemaVersion)){ ; } else { abortScanLab(signal, scanptr, tabPtr.p->getErrorCode(scanptr.p->scanSchemaVersion), true); return; } scanptr.p->scanNextFragId = 0; scanptr.p->m_booked_fragments_count= 0; scanptr.p->scanState = ScanRecord::WAIT_FRAGMENT_COUNT; if(!cachePtr.p->distributionKeyIndicator) { jam(); /************************************************* * THE FIRST STEP TO RECEIVE IS SUCCESSFULLY COMPLETED. * WE MUST FIRST GET THE NUMBER OF FRAGMENTS IN THE TABLE. ***************************************************/ DihFragCountReq * const req = (DihFragCountReq*)signal->getDataPtrSend(); req->m_connectionData = tcConnectptr.p->dihConnectptr; req->m_tableRef = scanptr.p->scanTableref; sendSignal(cdihblockref, GSN_DI_FCOUNTREQ, signal, DihFragCountReq::SignalLength, JBB); } else { signal->theData[0] = tcConnectptr.p->dihConnectptr; signal->theData[1] = tabPtr.i; signal->theData[2] = cachePtr.p->distributionKey; EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal, 3); UintR TerrorIndicator = signal->theData[0]; jamEntry(); if (TerrorIndicator != 0) { DihFragCountRef * const ref = (DihFragCountRef*)signal->getDataPtr(); ref->m_connectionData = tcConnectptr.i; ref->m_error = signal->theData[1]; execDI_FCOUNTREF(signal); return; } UintR Tdata1 = signal->theData[1]; scanptr.p->scanNextFragId = Tdata1; DihFragCountConf * const conf = (DihFragCountConf*)signal->getDataPtr(); conf->m_connectionData = tcConnectptr.i; conf->m_fragmentCount = 1; // Frag count execDI_FCOUNTCONF(signal); } return; }//Dbtc::diFcountReqLab() /******************************************************************** * execDI_FCOUNTCONF * * WE HAVE ASKED DIH ABOUT THE NUMBER OF FRAGMENTS IN THIS TABLE. * WE WILL NOW START A NUMBER OF PARALLEL SCAN PROCESSES. EACH OF * THESE WILL SCAN ONE FRAGMENT AT A TIME. THEY WILL CONTINUE THIS * UNTIL THERE ARE NO MORE FRAGMENTS TO SCAN OR UNTIL THE APPLICATION * CLOSES THE SCAN. ********************************************************************/ void Dbtc::execDI_FCOUNTCONF(Signal* signal) { jamEntry(); DihFragCountConf * const conf = (DihFragCountConf*)signal->getDataPtr(); tcConnectptr.i = conf->m_connectionData; Uint32 tfragCount = conf->m_fragmentCount; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.i = tcConnectptr.p->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ScanRecordPtr scanptr; scanptr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_FRAGMENT_COUNT); if (apiConnectptr.p->apiFailState == ZTRUE) { jam(); releaseScanResources(scanptr, true); handleApiFailState(signal, apiConnectptr.i); return; }//if if (tfragCount == 0) { jam(); abortScanLab(signal, scanptr, ZNO_FRAGMENT_ERROR, true); return; }//if /** * Check so that the table is not being dropped */ TableRecordPtr tabPtr; tabPtr.i = scanptr.p->scanTableref; tabPtr.p = &tableRecord[tabPtr.i]; if (tabPtr.p->checkTable(scanptr.p->scanSchemaVersion)){ ; } else { abortScanLab(signal, scanptr, tabPtr.p->getErrorCode(scanptr.p->scanSchemaVersion), true); return; } scanptr.p->scanParallel = tfragCount; scanptr.p->scanNoFrag = tfragCount; scanptr.p->scanState = ScanRecord::RUNNING; setApiConTimer(apiConnectptr.i, 0, __LINE__); updateBuddyTimer(apiConnectptr); ScanFragRecPtr ptr; ScanFragList list(c_scan_frag_pool, scanptr.p->m_running_scan_frags); for (list.first(ptr); !ptr.isNull() && tfragCount; list.next(ptr), tfragCount--){ jam(); ptr.p->lqhBlockref = 0; ptr.p->startFragTimer(ctcTimer); ptr.p->scanFragId = scanptr.p->scanNextFragId++; ptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; ptr.p->startFragTimer(ctcTimer); signal->theData[0] = tcConnectptr.p->dihConnectptr; signal->theData[1] = ptr.i; signal->theData[2] = scanptr.p->scanTableref; signal->theData[3] = ptr.p->scanFragId; sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB); }//for ScanFragList queued(c_scan_frag_pool, scanptr.p->m_queued_scan_frags); for (; !ptr.isNull();) { ptr.p->m_ops = 0; ptr.p->m_totalLen = 0; ptr.p->m_scan_frag_conf_status = 1; ptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY; ptr.p->stopFragTimer(); ScanFragRecPtr tmp = ptr; list.next(ptr); list.remove(tmp); queued.add(tmp); scanptr.p->m_queued_count++; } }//Dbtc::execDI_FCOUNTCONF() /****************************************************** * execDI_FCOUNTREF ******************************************************/ void Dbtc::execDI_FCOUNTREF(Signal* signal) { jamEntry(); DihFragCountRef * const ref = (DihFragCountRef*)signal->getDataPtr(); tcConnectptr.i = ref->m_connectionData; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); const Uint32 errCode = ref->m_error; apiConnectptr.i = tcConnectptr.p->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ScanRecordPtr scanptr; scanptr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_FRAGMENT_COUNT); if (apiConnectptr.p->apiFailState == ZTRUE) { jam(); releaseScanResources(scanptr, true); handleApiFailState(signal, apiConnectptr.i); return; }//if abortScanLab(signal, scanptr, errCode, true); }//Dbtc::execDI_FCOUNTREF() void Dbtc::abortScanLab(Signal* signal, ScanRecordPtr scanptr, Uint32 errCode, bool not_started) { scanTabRefLab(signal, errCode); releaseScanResources(scanptr, not_started); }//Dbtc::abortScanLab() void Dbtc::releaseScanResources(ScanRecordPtr scanPtr, bool not_started) { if (apiConnectptr.p->cachePtr != RNIL) { cachePtr.i = apiConnectptr.p->cachePtr; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); releaseKeys(); releaseAttrinfo(); }//if tcConnectptr.i = scanPtr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); releaseTcCon(); if (not_started) { jam(); ScanFragList run(c_scan_frag_pool, scanPtr.p->m_running_scan_frags); ScanFragList queue(c_scan_frag_pool, scanPtr.p->m_queued_scan_frags); run.release(); queue.release(); } ndbrequire(scanPtr.p->m_running_scan_frags.isEmpty()); ndbrequire(scanPtr.p->m_queued_scan_frags.isEmpty()); ndbrequire(scanPtr.p->m_delivered_scan_frags.isEmpty()); ndbassert(scanPtr.p->scanApiRec == apiConnectptr.i); ndbassert(apiConnectptr.p->apiScanRec == scanPtr.i); // link into free list scanPtr.p->nextScan = cfirstfreeScanrec; scanPtr.p->scanState = ScanRecord::IDLE; scanPtr.p->scanTcrec = RNIL; scanPtr.p->scanApiRec = RNIL; cfirstfreeScanrec = scanPtr.i; apiConnectptr.p->apiScanRec = RNIL; apiConnectptr.p->apiConnectstate = CS_CONNECTED; setApiConTimer(apiConnectptr.i, 0, __LINE__); }//Dbtc::releaseScanResources() /**************************************************************** * execDIGETPRIMCONF * * WE HAVE RECEIVED THE PRIMARY NODE OF THIS FRAGMENT. * WE ARE NOW READY TO ASK FOR PERMISSION TO LOAD THIS * SPECIFIC NODE WITH A SCAN OPERATION. ****************************************************************/ void Dbtc::execDIGETPRIMCONF(Signal* signal) { jamEntry(); // tcConnectptr.i in theData[0] is not used scanFragptr.i = signal->theData[1]; c_scan_frag_pool.getPtr(scanFragptr); tnodeid = signal->theData[2]; arrGuard(tnodeid, MAX_NDB_NODES); ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF); scanFragptr.p->stopFragTimer(); ScanRecordPtr scanptr; scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); /** * This must be false as select count(*) otherwise * can "pass" committing on backup fragments and * get incorrect row count */ if(false && ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) { jam(); Uint32 max = 3+signal->theData[6]; Uint32 nodeid = getOwnNodeId(); for(Uint32 i = 3; itheData[i] == nodeid) { jam(); tnodeid = nodeid; break; } } { /** * Check table */ TableRecordPtr tabPtr; tabPtr.i = scanptr.p->scanTableref; ptrAss(tabPtr, tableRecord); Uint32 schemaVersion = scanptr.p->scanSchemaVersion; if(tabPtr.p->checkTable(schemaVersion) == false){ jam(); ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(scanFragptr); scanError(signal, scanptr, tabPtr.p->getErrorCode(schemaVersion)); return; } } tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.i = scanptr.p->scanApiRec; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); cachePtr.i = apiConnectptr.p->cachePtr; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); switch (scanptr.p->scanState) { case ScanRecord::CLOSING_SCAN: jam(); updateBuddyTimer(apiConnectptr); { ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(scanFragptr); } close_scan_req_send_conf(signal, scanptr); return; default: jam(); /*empty*/; break; }//switch Uint32 ref = calcLqhBlockRef(tnodeid); scanFragptr.p->lqhBlockref = ref; scanFragptr.p->m_connectCount = getNodeInfo(tnodeid).m_connectCount; sendScanFragReq(signal, scanptr.p, scanFragptr.p); if(ERROR_INSERTED(8035)) globalTransporterRegistry.performSend(); attrbufptr.i = cachePtr.p->firstAttrbuf; while (attrbufptr.i != RNIL) { jam(); ptrCheckGuard(attrbufptr, cattrbufFilesize, attrbufRecord); sendAttrinfo(signal, scanFragptr.i, attrbufptr.p, ref); attrbufptr.i = attrbufptr.p->attrbuf[ZINBUF_NEXT]; if(ERROR_INSERTED(8035)) globalTransporterRegistry.performSend(); }//while scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; scanFragptr.p->startFragTimer(ctcTimer); updateBuddyTimer(apiConnectptr); /********************************************* * WE HAVE NOW STARTED A FRAGMENT SCAN. NOW * WAIT FOR THE FIRST SCANNED RECORDS *********************************************/ }//Dbtc::execDIGETPRIMCONF /*************************************************** * execDIGETPRIMREF * * WE ARE NOW FORCED TO STOP THE SCAN. THIS ERROR * IS NOT RECOVERABLE SINCE THERE IS A PROBLEM WITH * FINDING A PRIMARY REPLICA OF A CERTAIN FRAGMENT. ***************************************************/ void Dbtc::execDIGETPRIMREF(Signal* signal) { jamEntry(); // tcConnectptr.i in theData[0] is not used. scanFragptr.i = signal->theData[1]; const Uint32 errCode = signal->theData[2]; c_scan_frag_pool.getPtr(scanFragptr); ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::WAIT_GET_PRIMCONF); ScanRecordPtr scanptr; scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(scanFragptr); scanError(signal, scanptr, errCode); }//Dbtc::execDIGETPRIMREF() /** * Dbtc::execSCAN_FRAGREF * Our attempt to scan a fragment was refused * set error code and close all other fragment * scan's belonging to this scan */ void Dbtc::execSCAN_FRAGREF(Signal* signal) { const ScanFragRef * const ref = (ScanFragRef *)&signal->theData[0]; jamEntry(); const Uint32 errCode = ref->errorCode; scanFragptr.i = ref->senderData; c_scan_frag_pool.getPtr(scanFragptr); ScanRecordPtr scanptr; scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); apiConnectptr.i = scanptr.p->scanApiRec; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); Uint32 transid1 = apiConnectptr.p->transid[0] ^ ref->transId1; Uint32 transid2 = apiConnectptr.p->transid[1] ^ ref->transId2; transid1 = transid1 | transid2; if (transid1 != 0) { jam(); systemErrorLab(signal, __LINE__); }//if /** * Set errorcode, close connection to this lqh fragment, * stop fragment timer and call scanFragError to start * close of the other fragment scans */ ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE); { scanFragptr.p->scanFragState = ScanFragRec::COMPLETED; ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(scanFragptr); scanFragptr.p->stopFragTimer(); } scanError(signal, scanptr, errCode); }//Dbtc::execSCAN_FRAGREF() /** * Dbtc::scanError * * Called when an error occurs during */ void Dbtc::scanError(Signal* signal, ScanRecordPtr scanptr, Uint32 errorCode) { jam(); ScanRecord* scanP = scanptr.p; DEBUG("scanError, errorCode = "<< errorCode << ", scanState = " << scanptr.p->scanState); apiConnectptr.i = scanP->scanApiRec; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ndbrequire(apiConnectptr.p->apiScanRec == scanptr.i); if(scanP->scanState == ScanRecord::CLOSING_SCAN){ jam(); close_scan_req_send_conf(signal, scanptr); return; } ndbrequire(scanP->scanState == ScanRecord::RUNNING); /** * Close scan wo/ having received an order to do so */ close_scan_req(signal, scanptr, false); const bool apiFail = (apiConnectptr.p->apiFailState == ZTRUE); if(apiFail){ jam(); return; } ScanTabRef * ref = (ScanTabRef*)&signal->theData[0]; ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect; ref->transId1 = apiConnectptr.p->transid[0]; ref->transId2 = apiConnectptr.p->transid[1]; ref->errorCode = errorCode; ref->closeNeeded = 1; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABREF, signal, ScanTabRef::SignalLength, JBB); }//Dbtc::scanError() /************************************************************ * execSCAN_FRAGCONF * * A NUMBER OF OPERATIONS HAVE BEEN COMPLETED IN THIS * FRAGMENT. TAKE CARE OF AND ISSUE FURTHER ACTIONS. ************************************************************/ void Dbtc::execSCAN_FRAGCONF(Signal* signal) { Uint32 transid1, transid2, total_len; jamEntry(); const ScanFragConf * const conf = (ScanFragConf*)&signal->theData[0]; const Uint32 noCompletedOps = conf->completedOps; const Uint32 status = conf->fragmentCompleted; scanFragptr.i = conf->senderData; c_scan_frag_pool.getPtr(scanFragptr); ScanRecordPtr scanptr; scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); apiConnectptr.i = scanptr.p->scanApiRec; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); transid1 = apiConnectptr.p->transid[0] ^ conf->transId1; transid2 = apiConnectptr.p->transid[1] ^ conf->transId2; total_len= conf->total_len; transid1 = transid1 | transid2; if (transid1 != 0) { jam(); systemErrorLab(signal, __LINE__); }//if ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE); if(scanptr.p->scanState == ScanRecord::CLOSING_SCAN){ jam(); if(status == 0){ /** * We have started closing = we sent a close -> ignore this */ return; } else { jam(); ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); run.release(scanFragptr); scanFragptr.p->stopFragTimer(); scanFragptr.p->scanFragState = ScanFragRec::COMPLETED; } close_scan_req_send_conf(signal, scanptr); return; } if(noCompletedOps == 0 && status != 0 && scanptr.p->scanNextFragId+scanptr.p->m_booked_fragments_count < scanptr.p->scanNoFrag){ /** * Start on next fragment */ scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; scanFragptr.p->startFragTimer(ctcTimer); tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++; signal->theData[0] = tcConnectptr.p->dihConnectptr; signal->theData[1] = scanFragptr.i; signal->theData[2] = scanptr.p->scanTableref; signal->theData[3] = scanFragptr.p->scanFragId; sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB); return; } /* Uint32 totalLen = 0; for(Uint32 i = 0; iopReturnDataLen[i]; totalLen += tmp; } */ { ScanFragList run(c_scan_frag_pool, scanptr.p->m_running_scan_frags); ScanFragList queued(c_scan_frag_pool, scanptr.p->m_queued_scan_frags); run.remove(scanFragptr); queued.add(scanFragptr); scanptr.p->m_queued_count++; } scanFragptr.p->m_scan_frag_conf_status = status; scanFragptr.p->m_ops = noCompletedOps; scanFragptr.p->m_totalLen = total_len; scanFragptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY; scanFragptr.p->stopFragTimer(); if(scanptr.p->m_queued_count > /** Min */ 0){ jam(); sendScanTabConf(signal, scanptr); } }//Dbtc::execSCAN_FRAGCONF() /**************************************************************************** * execSCAN_NEXTREQ * * THE APPLICATION HAVE PROCESSED THE TUPLES TRANSFERRED AND IS NOW READY FOR * MORE. THIS SIGNAL IS ALSO USED TO CLOSE THE SCAN. ****************************************************************************/ void Dbtc::execSCAN_NEXTREQ(Signal* signal) { const ScanNextReq * const req = (ScanNextReq *)&signal->theData[0]; const UintR transid1 = req->transId1; const UintR transid2 = req->transId2; const UintR stopScan = req->stopScan; jamEntry(); apiConnectptr.i = req->apiConnectPtr; if (apiConnectptr.i >= capiConnectFilesize) { jam(); warningHandlerLab(signal, __LINE__); return; }//if ptrAss(apiConnectptr, apiConnectRecord); /** * Check transid */ const UintR ctransid1 = apiConnectptr.p->transid[0] ^ transid1; const UintR ctransid2 = apiConnectptr.p->transid[1] ^ transid2; if ((ctransid1 | ctransid2) != 0){ ScanTabRef * ref = (ScanTabRef*)&signal->theData[0]; ref->apiConnectPtr = apiConnectptr.p->ndbapiConnect; ref->transId1 = transid1; ref->transId2 = transid2; ref->errorCode = ZSTATE_ERROR; ref->closeNeeded = 0; sendSignal(signal->senderBlockRef(), GSN_SCAN_TABREF, signal, ScanTabRef::SignalLength, JBB); DEBUG("Wrong transid"); return; } /** * Check state of API connection */ if (apiConnectptr.p->apiConnectstate != CS_START_SCAN) { jam(); if (apiConnectptr.p->apiConnectstate == CS_CONNECTED) { jam(); /********************************************************************* * The application sends a SCAN_NEXTREQ after experiencing a time-out. * We will send a SCAN_TABREF to indicate a time-out occurred. *********************************************************************/ DEBUG("scanTabRefLab: ZSCANTIME_OUT_ERROR2"); ndbout_c("apiConnectptr(%d) -> abort", apiConnectptr.i); ndbrequire(false); //B2 indication of strange things going on scanTabRefLab(signal, ZSCANTIME_OUT_ERROR2); return; } DEBUG("scanTabRefLab: ZSTATE_ERROR"); DEBUG(" apiConnectstate="<apiConnectstate); ndbrequire(false); //B2 indication of strange things going on scanTabRefLab(signal, ZSTATE_ERROR); return; }//if /******************************************************* * START THE ACTUAL LOGIC OF SCAN_NEXTREQ. ********************************************************/ // Stop the timer that is used to check for timeout in the API setApiConTimer(apiConnectptr.i, 0, __LINE__); ScanRecordPtr scanptr; scanptr.i = apiConnectptr.p->apiScanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); ScanRecord* scanP = scanptr.p; const Uint32 len = signal->getLength() - 4; if (stopScan == ZTRUE) { jam(); /********************************************************************* * APPLICATION IS CLOSING THE SCAN. **********************************************************************/ close_scan_req(signal, scanptr, true); return; }//if if (scanptr.p->scanState == ScanRecord::CLOSING_SCAN){ jam(); /** * The scan is closing (typically due to error) * but the API hasn't understood it yet * * Wait for API close request */ return; } // Copy op ptrs so I dont overwrite them when sending... memcpy(signal->getDataPtrSend()+25, signal->getDataPtr()+4, 4 * len); ScanFragNextReq tmp; tmp.closeFlag = ZFALSE; tmp.transId1 = apiConnectptr.p->transid[0]; tmp.transId2 = apiConnectptr.p->transid[1]; tmp.batch_size_rows = scanP->batch_size_rows; tmp.batch_size_bytes = scanP->batch_byte_size; ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags); ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags); for(Uint32 i = 0 ; itheData[i+25]; c_scan_frag_pool.getPtr(scanFragptr); ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::DELIVERED); scanFragptr.p->startFragTimer(ctcTimer); scanFragptr.p->m_ops = 0; if(scanFragptr.p->m_scan_frag_conf_status) { /** * last scan was complete */ jam(); ndbrequire(scanptr.p->scanNextFragId < scanptr.p->scanNoFrag); jam(); ndbassert(scanptr.p->m_booked_fragments_count); scanptr.p->m_booked_fragments_count--; scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++; signal->theData[0] = tcConnectptr.p->dihConnectptr; signal->theData[1] = scanFragptr.i; signal->theData[2] = scanptr.p->scanTableref; signal->theData[3] = scanFragptr.p->scanFragId; sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB); } else { jam(); scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; ScanFragNextReq * req = (ScanFragNextReq*)signal->getDataPtrSend(); * req = tmp; req->senderData = scanFragptr.i; sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, ScanFragNextReq::SignalLength, JBB); } delivered.remove(scanFragptr); running.add(scanFragptr); }//for }//Dbtc::execSCAN_NEXTREQ() void Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){ ScanRecord* scanP = scanPtr.p; ndbrequire(scanPtr.p->scanState != ScanRecord::IDLE); ScanRecord::ScanState old = scanPtr.p->scanState; scanPtr.p->scanState = ScanRecord::CLOSING_SCAN; scanPtr.p->m_close_scan_req = req_received; if (old == ScanRecord::WAIT_FRAGMENT_COUNT) { jam(); scanPtr.p->scanState = old; return; // Will continue on execDI_FCOUNTCONF } /** * Queue : Action * ============= : ================= * completed : - * running : close -> LQH * delivered w/ : close -> LQH * delivered wo/ : move to completed * queued w/ : close -> LQH * queued wo/ : move to completed */ ScanFragNextReq * nextReq = (ScanFragNextReq*)&signal->theData[0]; nextReq->closeFlag = ZTRUE; nextReq->transId1 = apiConnectptr.p->transid[0]; nextReq->transId2 = apiConnectptr.p->transid[1]; { ScanFragRecPtr ptr; ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags); ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags); ScanFragList queued(c_scan_frag_pool, scanP->m_queued_scan_frags); // Close running for(running.first(ptr); !ptr.isNull(); ){ ScanFragRecPtr curr = ptr; // Remove while iterating... running.next(ptr); switch(curr.p->scanFragState){ case ScanFragRec::IDLE: jam(); // real early abort ndbrequire(old == ScanRecord::WAIT_AI); running.release(curr); continue; case ScanFragRec::WAIT_GET_PRIMCONF: jam(); continue; case ScanFragRec::LQH_ACTIVE: jam(); break; default: jamLine(curr.p->scanFragState); ndbrequire(false); } curr.p->startFragTimer(ctcTimer); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; nextReq->senderData = curr.i; sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, ScanFragNextReq::SignalLength, JBB); } // Close delivered for(delivered.first(ptr); !ptr.isNull(); ){ jam(); ScanFragRecPtr curr = ptr; // Remove while iterating... delivered.next(ptr); ndbrequire(curr.p->scanFragState == ScanFragRec::DELIVERED); delivered.remove(curr); if(curr.p->m_ops > 0 && curr.p->m_scan_frag_conf_status == 0){ jam(); running.add(curr); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; curr.p->startFragTimer(ctcTimer); nextReq->senderData = curr.i; sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, ScanFragNextReq::SignalLength, JBB); } else { jam(); c_scan_frag_pool.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); } }//for /** * All queued with data should be closed */ for(queued.first(ptr); !ptr.isNull(); ){ jam(); ndbrequire(ptr.p->scanFragState == ScanFragRec::QUEUED_FOR_DELIVERY); ScanFragRecPtr curr = ptr; // Remove while iterating... queued.next(ptr); queued.remove(curr); scanP->m_queued_count--; if(curr.p->m_ops > 0){ jam(); running.add(curr); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; curr.p->startFragTimer(ctcTimer); nextReq->senderData = curr.i; sendSignal(curr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, ScanFragNextReq::SignalLength, JBB); } else { jam(); c_scan_frag_pool.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); } } } close_scan_req_send_conf(signal, scanPtr); } void Dbtc::close_scan_req_send_conf(Signal* signal, ScanRecordPtr scanPtr){ jam(); ndbrequire(scanPtr.p->m_queued_scan_frags.isEmpty()); ndbrequire(scanPtr.p->m_delivered_scan_frags.isEmpty()); //ndbrequire(scanPtr.p->m_running_scan_frags.isEmpty()); #if 0 { ScanFragList comp(c_scan_frag_pool, scanPtr.p->m_completed_scan_frags); ScanFragRecPtr ptr; for(comp.first(ptr); !ptr.isNull(); comp.next(ptr)){ ndbrequire(ptr.p->scanFragTimer == 0); ndbrequire(ptr.p->scanFragState == ScanFragRec::COMPLETED); } } #endif if(!scanPtr.p->m_running_scan_frags.isEmpty()){ jam(); return; } const bool apiFail = (apiConnectptr.p->apiFailState == ZTRUE); if(!scanPtr.p->m_close_scan_req){ jam(); /** * The API hasn't order closing yet */ return; } Uint32 ref = apiConnectptr.p->ndbapiBlockref; if(!apiFail && ref){ jam(); ScanTabConf * conf = (ScanTabConf*)&signal->theData[0]; conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect; conf->requestInfo = ScanTabConf::EndOfData; conf->transId1 = apiConnectptr.p->transid[0]; conf->transId2 = apiConnectptr.p->transid[1]; sendSignal(ref, GSN_SCAN_TABCONF, signal, ScanTabConf::SignalLength, JBB); } releaseScanResources(scanPtr); if(apiFail){ jam(); /** * API has failed */ handleApiFailState(signal, apiConnectptr.i); } } Dbtc::ScanRecordPtr Dbtc::seizeScanrec(Signal* signal) { ScanRecordPtr scanptr; scanptr.i = cfirstfreeScanrec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); cfirstfreeScanrec = scanptr.p->nextScan; scanptr.p->nextScan = RNIL; ndbrequire(scanptr.p->scanState == ScanRecord::IDLE); return scanptr; }//Dbtc::seizeScanrec() void Dbtc::sendScanFragReq(Signal* signal, ScanRecord* scanP, ScanFragRec* scanFragP) { ScanFragReq * const req = (ScanFragReq *)&signal->theData[0]; Uint32 requestInfo = scanP->scanRequestInfo; ScanFragReq::setScanPrio(requestInfo, 1); apiConnectptr.i = scanP->scanApiRec; req->tableId = scanP->scanTableref; req->schemaVersion = scanP->scanSchemaVersion; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); req->senderData = scanFragptr.i; req->requestInfo = requestInfo; req->fragmentNoKeyLen = scanFragP->scanFragId | (scanP->scanKeyLen << 16); req->resultRef = apiConnectptr.p->ndbapiBlockref; req->savePointId = apiConnectptr.p->currSavePointId; req->transId1 = apiConnectptr.p->transid[0]; req->transId2 = apiConnectptr.p->transid[1]; req->clientOpPtr = scanFragP->m_apiPtr; req->batch_size_rows= scanP->batch_size_rows; req->batch_size_bytes= scanP->batch_byte_size; sendSignal(scanFragP->lqhBlockref, GSN_SCAN_FRAGREQ, signal, ScanFragReq::SignalLength, JBB); if(scanP->scanKeyLen > 0) { tcConnectptr.i = scanFragptr.i; packKeyData000Lab(signal, scanFragP->lqhBlockref, scanP->scanKeyLen); } updateBuddyTimer(apiConnectptr); scanFragP->startFragTimer(ctcTimer); }//Dbtc::sendScanFragReq() void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) { jam(); Uint32* ops = signal->getDataPtrSend()+4; Uint32 op_count = scanPtr.p->m_queued_count; if(4 + 3 * op_count > 25){ jam(); ops += 21; } int left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId; Uint32 booked = scanPtr.p->m_booked_fragments_count; ScanTabConf * conf = (ScanTabConf*)&signal->theData[0]; conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect; conf->requestInfo = op_count; conf->transId1 = apiConnectptr.p->transid[0]; conf->transId2 = apiConnectptr.p->transid[1]; ScanFragRecPtr ptr; { ScanFragList queued(c_scan_frag_pool, scanPtr.p->m_queued_scan_frags); ScanFragList delivered(c_scan_frag_pool,scanPtr.p->m_delivered_scan_frags); for(queued.first(ptr); !ptr.isNull(); ){ ndbrequire(ptr.p->scanFragState == ScanFragRec::QUEUED_FOR_DELIVERY); ScanFragRecPtr curr = ptr; // Remove while iterating... queued.next(ptr); bool done = curr.p->m_scan_frag_conf_status && (left <= (int)booked); if(curr.p->m_scan_frag_conf_status) booked++; * ops++ = curr.p->m_apiPtr; * ops++ = done ? RNIL : curr.i; * ops++ = (curr.p->m_totalLen << 10) + curr.p->m_ops; queued.remove(curr); if(!done){ delivered.add(curr); curr.p->scanFragState = ScanFragRec::DELIVERED; curr.p->stopFragTimer(); } else { c_scan_frag_pool.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); } } } scanPtr.p->m_booked_fragments_count = booked; if(scanPtr.p->m_delivered_scan_frags.isEmpty() && scanPtr.p->m_running_scan_frags.isEmpty()) { conf->requestInfo = op_count | ScanTabConf::EndOfData; releaseScanResources(scanPtr); } else { if (scanPtr.p->m_running_scan_frags.isEmpty()) { jam(); /** * All scan frags delivered...waiting for API */ setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); } } if(4 + 3 * op_count > 25){ jam(); LinearSectionPtr ptr[3]; ptr[0].p = signal->getDataPtrSend()+25; ptr[0].sz = 3 * op_count; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABCONF, signal, ScanTabConf::SignalLength, JBB, ptr, 1); } else { jam(); sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_SCAN_TABCONF, signal, ScanTabConf::SignalLength + 3 * op_count, JBB); } scanPtr.p->m_queued_count = 0; }//Dbtc::sendScanTabConf() void Dbtc::gcpTcfinished(Signal* signal) { signal->theData[0] = c_gcp_ref; signal->theData[1] = tcheckGcpId; sendSignal(cdihblockref, GSN_GCP_TCFINISHED, signal, 2, JBB); }//Dbtc::gcpTcfinished() void Dbtc::initApiConnect(Signal* signal) { Uint32 tiacTmp; Uint32 guard4; tiacTmp = capiConnectFilesize / 3; ndbrequire(tiacTmp > 0); guard4 = tiacTmp + 1; for (cachePtr.i = 0; cachePtr.i < guard4; cachePtr.i++) { refresh_watch_dog(); ptrAss(cachePtr, cacheRecord); cachePtr.p->firstAttrbuf = RNIL; cachePtr.p->lastAttrbuf = RNIL; cachePtr.p->firstKeybuf = RNIL; cachePtr.p->lastKeybuf = RNIL; cachePtr.p->nextCacheRec = cachePtr.i + 1; }//for cachePtr.i = tiacTmp; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); cachePtr.p->nextCacheRec = RNIL; cfirstfreeCacheRec = 0; guard4 = tiacTmp - 1; for (apiConnectptr.i = 0; apiConnectptr.i <= guard4; apiConnectptr.i++) { refresh_watch_dog(); jam(); ptrAss(apiConnectptr, apiConnectRecord); apiConnectptr.p->apiConnectstate = CS_DISCONNECTED; apiConnectptr.p->apiFailState = ZFALSE; setApiConTimer(apiConnectptr.i, 0, __LINE__); apiConnectptr.p->takeOverRec = (Uint8)Z8NIL; apiConnectptr.p->cachePtr = RNIL; apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1; apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; apiConnectptr.p->executingIndexOp = RNIL; apiConnectptr.p->buddyPtr = RNIL; apiConnectptr.p->currSavePointId = 0; apiConnectptr.p->m_transaction_nodes.clear(); apiConnectptr.p->singleUserMode = 0; }//for apiConnectptr.i = tiacTmp - 1; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->nextApiConnect = RNIL; cfirstfreeApiConnect = 0; guard4 = (2 * tiacTmp) - 1; for (apiConnectptr.i = tiacTmp; apiConnectptr.i <= guard4; apiConnectptr.i++) { refresh_watch_dog(); jam(); ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->apiConnectstate = CS_RESTART; apiConnectptr.p->apiFailState = ZFALSE; setApiConTimer(apiConnectptr.i, 0, __LINE__); apiConnectptr.p->takeOverRec = (Uint8)Z8NIL; apiConnectptr.p->cachePtr = RNIL; apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1; apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; apiConnectptr.p->executingIndexOp = RNIL; apiConnectptr.p->buddyPtr = RNIL; apiConnectptr.p->currSavePointId = 0; apiConnectptr.p->m_transaction_nodes.clear(); apiConnectptr.p->singleUserMode = 0; }//for apiConnectptr.i = (2 * tiacTmp) - 1; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->nextApiConnect = RNIL; cfirstfreeApiConnectCopy = tiacTmp; guard4 = (3 * tiacTmp) - 1; for (apiConnectptr.i = 2 * tiacTmp; apiConnectptr.i <= guard4; apiConnectptr.i++) { refresh_watch_dog(); jam(); ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); setApiConTimer(apiConnectptr.i, 0, __LINE__); apiConnectptr.p->apiFailState = ZFALSE; apiConnectptr.p->apiConnectstate = CS_RESTART; apiConnectptr.p->takeOverRec = (Uint8)Z8NIL; apiConnectptr.p->cachePtr = RNIL; apiConnectptr.p->nextApiConnect = apiConnectptr.i + 1; apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; apiConnectptr.p->executingIndexOp = RNIL; apiConnectptr.p->buddyPtr = RNIL; apiConnectptr.p->currSavePointId = 0; apiConnectptr.p->m_transaction_nodes.clear(); apiConnectptr.p->singleUserMode = 0; }//for apiConnectptr.i = (3 * tiacTmp) - 1; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); apiConnectptr.p->nextApiConnect = RNIL; cfirstfreeApiConnectFail = 2 * tiacTmp; }//Dbtc::initApiConnect() void Dbtc::initattrbuf(Signal* signal) { ndbrequire(cattrbufFilesize > 0); for (attrbufptr.i = 0; attrbufptr.i < cattrbufFilesize; attrbufptr.i++) { refresh_watch_dog(); jam(); ptrAss(attrbufptr, attrbufRecord); attrbufptr.p->attrbuf[ZINBUF_NEXT] = attrbufptr.i + 1; /* NEXT ATTRBUF */ }//for attrbufptr.i = cattrbufFilesize - 1; ptrAss(attrbufptr, attrbufRecord); attrbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL; /* NEXT ATTRBUF */ cfirstfreeAttrbuf = 0; }//Dbtc::initattrbuf() void Dbtc::initdatabuf(Signal* signal) { ndbrequire(cdatabufFilesize > 0); for (databufptr.i = 0; databufptr.i < cdatabufFilesize; databufptr.i++) { refresh_watch_dog(); ptrAss(databufptr, databufRecord); databufptr.p->nextDatabuf = databufptr.i + 1; }//for databufptr.i = cdatabufFilesize - 1; ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); databufptr.p->nextDatabuf = RNIL; cfirstfreeDatabuf = 0; }//Dbtc::initdatabuf() void Dbtc::initgcp(Signal* signal) { ndbrequire(cgcpFilesize > 0); for (gcpPtr.i = 0; gcpPtr.i < cgcpFilesize; gcpPtr.i++) { ptrAss(gcpPtr, gcpRecord); gcpPtr.p->nextGcp = gcpPtr.i + 1; }//for gcpPtr.i = cgcpFilesize - 1; ptrCheckGuard(gcpPtr, cgcpFilesize, gcpRecord); gcpPtr.p->nextGcp = RNIL; cfirstfreeGcp = 0; cfirstgcp = RNIL; clastgcp = RNIL; }//Dbtc::initgcp() void Dbtc::inithost(Signal* signal) { cpackedListIndex = 0; ndbrequire(chostFilesize > 0); for (hostptr.i = 0; hostptr.i < chostFilesize; hostptr.i++) { jam(); ptrAss(hostptr, hostRecord); hostptr.p->hostStatus = HS_DEAD; hostptr.p->inPackedList = false; hostptr.p->lqhTransStatus = LTS_IDLE; hostptr.p->noOfWordsTCKEYCONF = 0; hostptr.p->noOfWordsTCINDXCONF = 0; hostptr.p->noOfPackedWordsLqh = 0; hostptr.p->hostLqhBlockRef = calcLqhBlockRef(hostptr.i); hostptr.p->m_nf_bits = 0; }//for c_alive_nodes.clear(); }//Dbtc::inithost() void Dbtc::initialiseRecordsLab(Signal* signal, UintR Tdata0, Uint32 retRef, Uint32 retData) { switch (Tdata0) { case 0: jam(); initApiConnect(signal); break; case 1: jam(); initattrbuf(signal); break; case 2: jam(); initdatabuf(signal); break; case 3: jam(); initgcp(signal); break; case 4: jam(); inithost(signal); break; case 5: jam(); // UNUSED Free to initialise something break; case 6: jam(); initTable(signal); break; case 7: jam(); initialiseScanrec(signal); break; case 8: jam(); initialiseScanOprec(signal); break; case 9: jam(); initialiseScanFragrec(signal); break; case 10: jam(); initialiseTcConnect(signal); break; case 11: jam(); initTcFail(signal); { ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); conf->senderRef = reference(); conf->senderData = retData; sendSignal(retRef, GSN_READ_CONFIG_CONF, signal, ReadConfigConf::SignalLength, JBB); } return; break; default: jam(); systemErrorLab(signal, __LINE__); return; break; }//switch signal->theData[0] = TcContinueB::ZINITIALISE_RECORDS; signal->theData[1] = Tdata0 + 1; signal->theData[2] = 0; signal->theData[3] = retRef; signal->theData[4] = retData; sendSignal(DBTC_REF, GSN_CONTINUEB, signal, 5, JBB); } /* ========================================================================= */ /* ======= INITIALISE_SCANREC ======= */ /* */ /* ========================================================================= */ void Dbtc::initialiseScanrec(Signal* signal) { ScanRecordPtr scanptr; ndbrequire(cscanrecFileSize > 0); for (scanptr.i = 0; scanptr.i < cscanrecFileSize; scanptr.i++) { refresh_watch_dog(); jam(); ptrAss(scanptr, scanRecord); new (scanptr.p) ScanRecord(); scanptr.p->scanState = ScanRecord::IDLE; scanptr.p->scanApiRec = RNIL; scanptr.p->nextScan = scanptr.i + 1; }//for scanptr.i = cscanrecFileSize - 1; ptrAss(scanptr, scanRecord); scanptr.p->nextScan = RNIL; cfirstfreeScanrec = 0; }//Dbtc::initialiseScanrec() void Dbtc::initialiseScanFragrec(Signal* signal) { }//Dbtc::initialiseScanFragrec() void Dbtc::initialiseScanOprec(Signal* signal) { }//Dbtc::initialiseScanOprec() void Dbtc::initTable(Signal* signal) { ndbrequire(ctabrecFilesize > 0); for (tabptr.i = 0; tabptr.i < ctabrecFilesize; tabptr.i++) { refresh_watch_dog(); ptrAss(tabptr, tableRecord); tabptr.p->currentSchemaVersion = 0; tabptr.p->m_flags = 0; tabptr.p->set_storedTable(true); tabptr.p->tableType = 0; tabptr.p->set_enabled(false); tabptr.p->set_dropping(false); tabptr.p->noOfKeyAttr = 0; tabptr.p->hasCharAttr = 0; tabptr.p->noOfDistrKeys = 0; tabptr.p->hasVarKeys = 0; }//for }//Dbtc::initTable() void Dbtc::initialiseTcConnect(Signal* signal) { ndbrequire(ctcConnectFilesize >= 2); // Place half of tcConnectptr's in cfirstfreeTcConnectFail list Uint32 titcTmp = ctcConnectFilesize / 2; for (tcConnectptr.i = 0; tcConnectptr.i < titcTmp; tcConnectptr.i++) { refresh_watch_dog(); jam(); ptrAss(tcConnectptr, tcConnectRecord); tcConnectptr.p->tcConnectstate = OS_RESTART; tcConnectptr.p->apiConnect = RNIL; tcConnectptr.p->noOfNodes = 0; tcConnectptr.p->nextTcConnect = tcConnectptr.i + 1; }//for tcConnectptr.i = titcTmp - 1; ptrAss(tcConnectptr, tcConnectRecord); tcConnectptr.p->nextTcConnect = RNIL; cfirstfreeTcConnectFail = 0; // Place other half in cfirstfreeTcConnect list for (tcConnectptr.i = titcTmp; tcConnectptr.i < ctcConnectFilesize; tcConnectptr.i++) { refresh_watch_dog(); jam(); ptrAss(tcConnectptr, tcConnectRecord); tcConnectptr.p->tcConnectstate = OS_RESTART; tcConnectptr.p->apiConnect = RNIL; tcConnectptr.p->noOfNodes = 0; tcConnectptr.p->nextTcConnect = tcConnectptr.i + 1; }//for tcConnectptr.i = ctcConnectFilesize - 1; ptrAss(tcConnectptr, tcConnectRecord); tcConnectptr.p->nextTcConnect = RNIL; cfirstfreeTcConnect = titcTmp; c_counters.cconcurrentOp = 0; }//Dbtc::initialiseTcConnect() /* ------------------------------------------------------------------------- */ /* ---- LINK A GLOBAL CHECKPOINT RECORD INTO THE LIST WITH TRANSACTIONS */ /* WAITING FOR COMPLETION. */ /* ------------------------------------------------------------------------- */ void Dbtc::linkGciInGcilist(Signal* signal) { GcpRecordPtr tmpGcpPointer; if (cfirstgcp == RNIL) { jam(); cfirstgcp = gcpPtr.i; } else { jam(); tmpGcpPointer.i = clastgcp; ptrCheckGuard(tmpGcpPointer, cgcpFilesize, gcpRecord); tmpGcpPointer.p->nextGcp = gcpPtr.i; }//if clastgcp = gcpPtr.i; }//Dbtc::linkGciInGcilist() /* ------------------------------------------------------------------------- */ /* ------- LINK SECONDARY KEY BUFFER IN OPERATION RECORD ------- */ /* ------------------------------------------------------------------------- */ void Dbtc::linkKeybuf(Signal* signal) { seizeDatabuf(signal); tmpDatabufptr.i = cachePtr.p->lastKeybuf; cachePtr.p->lastKeybuf = databufptr.i; if (tmpDatabufptr.i == RNIL) { jam(); cachePtr.p->firstKeybuf = databufptr.i; } else { jam(); ptrCheckGuard(tmpDatabufptr, cdatabufFilesize, databufRecord); tmpDatabufptr.p->nextDatabuf = databufptr.i; }//if }//Dbtc::linkKeybuf() /* ------------------------------------------------------------------------- */ /* ------- LINK A TC CONNECT RECORD INTO THE API LIST OF TC CONNECTIONS --- */ /* ------------------------------------------------------------------------- */ void Dbtc::linkTcInConnectionlist(Signal* signal) { /* POINTER FOR THE CONNECT_RECORD */ TcConnectRecordPtr ltcTcConnectptr; tcConnectptr.p->nextTcConnect = RNIL; ltcTcConnectptr.i = apiConnectptr.p->lastTcConnect; ptrCheck(ltcTcConnectptr, ctcConnectFilesize, tcConnectRecord); apiConnectptr.p->lastTcConnect = tcConnectptr.i; if (ltcTcConnectptr.i == RNIL) { jam(); apiConnectptr.p->firstTcConnect = tcConnectptr.i; } else { jam(); ptrGuard(ltcTcConnectptr); ltcTcConnectptr.p->nextTcConnect = tcConnectptr.i; }//if }//Dbtc::linkTcInConnectionlist() /*---------------------------------------------------------------------------*/ /* RELEASE_ABORT_RESOURCES */ /* THIS CODE RELEASES ALL RESOURCES AFTER AN ABORT OF A TRANSACTION AND ALSO */ /* SENDS THE ABORT DECISION TO THE APPLICATION. */ /*---------------------------------------------------------------------------*/ void Dbtc::releaseAbortResources(Signal* signal) { TcConnectRecordPtr rarTcConnectptr; c_counters.cabortCount++; if (apiConnectptr.p->cachePtr != RNIL) { cachePtr.i = apiConnectptr.p->cachePtr; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); releaseAttrinfo(); releaseKeys(); }//if tcConnectptr.i = apiConnectptr.p->firstTcConnect; while (tcConnectptr.i != RNIL) { jam(); ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); // Clear any markers that were set in CS_RECEIVING state clearCommitAckMarker(apiConnectptr.p, tcConnectptr.p); rarTcConnectptr.i = tcConnectptr.p->nextTcConnect; releaseTcCon(); tcConnectptr.i = rarTcConnectptr.i; }//while apiConnectptr.p->firstTcConnect = RNIL; apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->m_transaction_nodes.clear(); apiConnectptr.p->singleUserMode = 0; // MASV let state be CS_ABORTING until all // signals in the "air" have been received. Reset to CS_CONNECTED // will be done when a TCKEYREQ with start flag is recieved // or releaseApiCon is called // apiConnectptr.p->apiConnectstate = CS_CONNECTED; apiConnectptr.p->apiConnectstate = CS_ABORTING; apiConnectptr.p->abortState = AS_IDLE; releaseAllSeizedIndexOperations(apiConnectptr.p); if(apiConnectptr.p->m_exec_flag || apiConnectptr.p->apiFailState == ZTRUE){ jam(); bool ok = false; Uint32 blockRef = apiConnectptr.p->ndbapiBlockref; ReturnSignal ret = apiConnectptr.p->returnsignal; apiConnectptr.p->returnsignal = RS_NO_RETURN; apiConnectptr.p->m_exec_flag = 0; switch(ret){ case RS_TCROLLBACKCONF: jam(); ok = true; signal->theData[0] = apiConnectptr.p->ndbapiConnect; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; sendSignal(blockRef, GSN_TCROLLBACKCONF, signal, 3, JBB); break; case RS_TCROLLBACKREP:{ jam(); ok = true; TcRollbackRep * const tcRollbackRep = (TcRollbackRep *) signal->getDataPtr(); tcRollbackRep->connectPtr = apiConnectptr.p->ndbapiConnect; tcRollbackRep->transId[0] = apiConnectptr.p->transid[0]; tcRollbackRep->transId[1] = apiConnectptr.p->transid[1]; tcRollbackRep->returnCode = apiConnectptr.p->returncode; tcRollbackRep->errorData = apiConnectptr.p->errorData; sendSignal(blockRef, GSN_TCROLLBACKREP, signal, TcRollbackRep::SignalLength, JBB); } break; case RS_NO_RETURN: jam(); ok = true; break; case RS_TCKEYCONF: case RS_TC_COMMITCONF: break; } if(!ok){ jam(); ndbout_c("returnsignal = %d", apiConnectptr.p->returnsignal); sendSystemError(signal, __LINE__); }//if } setApiConTimer(apiConnectptr.i, 0, 100000+c_apiConTimer_line[apiConnectptr.i]); if (apiConnectptr.p->apiFailState == ZTRUE) { jam(); handleApiFailState(signal, apiConnectptr.i); return; }//if }//Dbtc::releaseAbortResources() void Dbtc::releaseApiCon(Signal* signal, UintR TapiConnectPtr) { ApiConnectRecordPtr TlocalApiConnectptr; TlocalApiConnectptr.i = TapiConnectPtr; ptrCheckGuard(TlocalApiConnectptr, capiConnectFilesize, apiConnectRecord); TlocalApiConnectptr.p->nextApiConnect = cfirstfreeApiConnect; cfirstfreeApiConnect = TlocalApiConnectptr.i; setApiConTimer(TlocalApiConnectptr.i, 0, __LINE__); TlocalApiConnectptr.p->apiConnectstate = CS_DISCONNECTED; ndbassert(TlocalApiConnectptr.p->m_transaction_nodes.isclear()); ndbassert(TlocalApiConnectptr.p->apiScanRec == RNIL); TlocalApiConnectptr.p->ndbapiBlockref = 0; }//Dbtc::releaseApiCon() void Dbtc::releaseApiConnectFail(Signal* signal) { apiConnectptr.p->apiConnectstate = CS_RESTART; apiConnectptr.p->takeOverRec = (Uint8)Z8NIL; setApiConTimer(apiConnectptr.i, 0, __LINE__); apiConnectptr.p->nextApiConnect = cfirstfreeApiConnectFail; cfirstfreeApiConnectFail = apiConnectptr.i; }//Dbtc::releaseApiConnectFail() void Dbtc::releaseGcp(Signal* signal) { ptrGuard(gcpPtr); gcpPtr.p->nextGcp = cfirstfreeGcp; cfirstfreeGcp = gcpPtr.i; }//Dbtc::releaseGcp() void Dbtc::releaseKeys() { UintR Tmp; databufptr.i = cachePtr.p->firstKeybuf; while (databufptr.i != RNIL) { jam(); ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); Tmp = databufptr.p->nextDatabuf; databufptr.p->nextDatabuf = cfirstfreeDatabuf; cfirstfreeDatabuf = databufptr.i; databufptr.i = Tmp; }//while cachePtr.p->firstKeybuf = RNIL; cachePtr.p->lastKeybuf = RNIL; }//Dbtc::releaseKeys() void Dbtc::releaseTcConnectFail(Signal* signal) { ptrGuard(tcConnectptr); tcConnectptr.p->nextTcConnect = cfirstfreeTcConnectFail; cfirstfreeTcConnectFail = tcConnectptr.i; }//Dbtc::releaseTcConnectFail() void Dbtc::seizeApiConnect(Signal* signal) { if (cfirstfreeApiConnect != RNIL) { jam(); terrorCode = ZOK; apiConnectptr.i = cfirstfreeApiConnect; /* ASSIGN A FREE RECORD FROM */ ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); cfirstfreeApiConnect = apiConnectptr.p->nextApiConnect; apiConnectptr.p->nextApiConnect = RNIL; setApiConTimer(apiConnectptr.i, 0, __LINE__); apiConnectptr.p->apiConnectstate = CS_CONNECTED; /* STATE OF CONNECTION */ apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; } else { jam(); terrorCode = ZNO_FREE_API_CONNECTION; }//if }//Dbtc::seizeApiConnect() void Dbtc::seizeApiConnectFail(Signal* signal) { apiConnectptr.i = cfirstfreeApiConnectFail; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); cfirstfreeApiConnectFail = apiConnectptr.p->nextApiConnect; }//Dbtc::seizeApiConnectFail() void Dbtc::seizeDatabuf(Signal* signal) { databufptr.i = cfirstfreeDatabuf; ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); cfirstfreeDatabuf = databufptr.p->nextDatabuf; databufptr.p->nextDatabuf = RNIL; }//Dbtc::seizeDatabuf() void Dbtc::seizeTcConnect(Signal* signal) { tcConnectptr.i = cfirstfreeTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); cfirstfreeTcConnect = tcConnectptr.p->nextTcConnect; c_counters.cconcurrentOp++; tcConnectptr.p->isIndexOp = false; }//Dbtc::seizeTcConnect() void Dbtc::seizeTcConnectFail(Signal* signal) { tcConnectptr.i = cfirstfreeTcConnectFail; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); cfirstfreeTcConnectFail = tcConnectptr.p->nextTcConnect; }//Dbtc::seizeTcConnectFail() void Dbtc::sendAttrinfo(Signal* signal, UintR TattrinfoPtr, AttrbufRecord * const regAttrPtr, UintR TBref) { UintR TdataPos; UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6, sig7; ApiConnectRecord * const regApiPtr = apiConnectptr.p; TdataPos = regAttrPtr->attrbuf[ZINBUF_DATA_LEN]; sig0 = TattrinfoPtr; sig1 = regApiPtr->transid[0]; sig2 = regApiPtr->transid[1]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->theData[2] = sig2; sig0 = regAttrPtr->attrbuf[0]; sig1 = regAttrPtr->attrbuf[1]; sig2 = regAttrPtr->attrbuf[2]; sig3 = regAttrPtr->attrbuf[3]; sig4 = regAttrPtr->attrbuf[4]; sig5 = regAttrPtr->attrbuf[5]; sig6 = regAttrPtr->attrbuf[6]; sig7 = regAttrPtr->attrbuf[7]; signal->theData[3] = sig0; signal->theData[4] = sig1; signal->theData[5] = sig2; signal->theData[6] = sig3; signal->theData[7] = sig4; signal->theData[8] = sig5; signal->theData[9] = sig6; signal->theData[10] = sig7; if (TdataPos > 8) { sig0 = regAttrPtr->attrbuf[8]; sig1 = regAttrPtr->attrbuf[9]; sig2 = regAttrPtr->attrbuf[10]; sig3 = regAttrPtr->attrbuf[11]; sig4 = regAttrPtr->attrbuf[12]; sig5 = regAttrPtr->attrbuf[13]; sig6 = regAttrPtr->attrbuf[14]; jam(); signal->theData[11] = sig0; signal->theData[12] = sig1; signal->theData[13] = sig2; signal->theData[14] = sig3; signal->theData[15] = sig4; signal->theData[16] = sig5; signal->theData[17] = sig6; if (TdataPos > 15) { sig0 = regAttrPtr->attrbuf[15]; sig1 = regAttrPtr->attrbuf[16]; sig2 = regAttrPtr->attrbuf[17]; sig3 = regAttrPtr->attrbuf[18]; sig4 = regAttrPtr->attrbuf[19]; sig5 = regAttrPtr->attrbuf[20]; sig6 = regAttrPtr->attrbuf[21]; jam(); signal->theData[18] = sig0; signal->theData[19] = sig1; signal->theData[20] = sig2; signal->theData[21] = sig3; signal->theData[22] = sig4; signal->theData[23] = sig5; signal->theData[24] = sig6; }//if }//if sendSignal(TBref, GSN_ATTRINFO, signal, TdataPos + 3, JBB); }//Dbtc::sendAttrinfo() void Dbtc::sendContinueTimeOutControl(Signal* signal, Uint32 TapiConPtr) { signal->theData[0] = TcContinueB::ZCONTINUE_TIME_OUT_CONTROL; signal->theData[1] = TapiConPtr; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//Dbtc::sendContinueTimeOutControl() void Dbtc::sendKeyinfo(Signal* signal, BlockReference TBRef, Uint32 len) { signal->theData[0] = tcConnectptr.i; signal->theData[1] = apiConnectptr.p->transid[0]; signal->theData[2] = apiConnectptr.p->transid[1]; signal->theData[3] = cdata[0]; signal->theData[4] = cdata[1]; signal->theData[5] = cdata[2]; signal->theData[6] = cdata[3]; signal->theData[7] = cdata[4]; signal->theData[8] = cdata[5]; signal->theData[9] = cdata[6]; signal->theData[10] = cdata[7]; signal->theData[11] = cdata[8]; signal->theData[12] = cdata[9]; signal->theData[13] = cdata[10]; signal->theData[14] = cdata[11]; signal->theData[15] = cdata[12]; signal->theData[16] = cdata[13]; signal->theData[17] = cdata[14]; signal->theData[18] = cdata[15]; signal->theData[19] = cdata[16]; signal->theData[20] = cdata[17]; signal->theData[21] = cdata[18]; signal->theData[22] = cdata[19]; sendSignal(TBRef, GSN_KEYINFO, signal, 3 + len, JBB); }//Dbtc::sendKeyinfo() void Dbtc::sendSystemError(Signal* signal, int line) { progError(line, NDBD_EXIT_NDBREQUIRE); }//Dbtc::sendSystemError() /* ========================================================================= */ /* ------- LINK ACTUAL GCP OUT OF LIST ------- */ /* ------------------------------------------------------------------------- */ void Dbtc::unlinkGcp(Signal* signal) { if (cfirstgcp == gcpPtr.i) { jam(); cfirstgcp = gcpPtr.p->nextGcp; if (gcpPtr.i == clastgcp) { jam(); clastgcp = RNIL; }//if } else { jam(); /* -------------------------------------------------------------------- * WE ARE TRYING TO REMOVE A GLOBAL CHECKPOINT WHICH WAS NOT THE OLDEST. * THIS IS A SYSTEM ERROR. * ------------------------------------------------------------------- */ sendSystemError(signal, __LINE__); }//if gcpPtr.p->nextGcp = cfirstfreeGcp; cfirstfreeGcp = gcpPtr.i; }//Dbtc::unlinkGcp() void Dbtc::execDUMP_STATE_ORD(Signal* signal) { DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0]; if(signal->theData[0] == DumpStateOrd::CommitAckMarkersSize){ infoEvent("TC: m_commitAckMarkerPool: %d free size: %d", m_commitAckMarkerPool.getNoOfFree(), m_commitAckMarkerPool.getSize()); } if(signal->theData[0] == DumpStateOrd::CommitAckMarkersDump){ infoEvent("TC: m_commitAckMarkerPool: %d free size: %d", m_commitAckMarkerPool.getNoOfFree(), m_commitAckMarkerPool.getSize()); CommitAckMarkerIterator iter; for(m_commitAckMarkerHash.first(iter); iter.curr.i != RNIL; m_commitAckMarkerHash.next(iter)){ infoEvent("CommitAckMarker: i = %d (0x%x, 0x%x)" " Api: %d Lghs(%d): %d %d %d %d bucket = %d", iter.curr.i, iter.curr.p->transid1, iter.curr.p->transid2, iter.curr.p->apiNodeId, iter.curr.p->noOfLqhs, iter.curr.p->lqhNodeId[0], iter.curr.p->lqhNodeId[1], iter.curr.p->lqhNodeId[2], iter.curr.p->lqhNodeId[3], iter.bucket); } } // Dump all ScanFragRecs if (dumpState->args[0] == DumpStateOrd::TcDumpAllScanFragRec){ Uint32 recordNo = 0; if (signal->getLength() == 1) infoEvent("TC: Dump all ScanFragRec - size: %d", cscanFragrecFileSize); else if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; dumpState->args[0] = DumpStateOrd::TcDumpOneScanFragRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); if (recordNo < cscanFragrecFileSize-1){ dumpState->args[0] = DumpStateOrd::TcDumpAllScanFragRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } } // Dump one ScanFragRec if (dumpState->args[0] == DumpStateOrd::TcDumpOneScanFragRec){ Uint32 recordNo = RNIL; if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; if (recordNo >= cscanFragrecFileSize) return; ScanFragRecPtr sfp; sfp.i = recordNo; c_scan_frag_pool.getPtr(sfp); infoEvent("Dbtc::ScanFragRec[%d]: state=%d fragid=%d", sfp.i, sfp.p->scanFragState, sfp.p->scanFragId); infoEvent(" nodeid=%d, timer=%d", refToNode(sfp.p->lqhBlockref), sfp.p->scanFragTimer); } // Dump all ScanRecords if (dumpState->args[0] == DumpStateOrd::TcDumpAllScanRec){ Uint32 recordNo = 0; if (signal->getLength() == 1) infoEvent("TC: Dump all ScanRecord - size: %d", cscanrecFileSize); else if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; dumpState->args[0] = DumpStateOrd::TcDumpOneScanRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); if (recordNo < cscanrecFileSize-1){ dumpState->args[0] = DumpStateOrd::TcDumpAllScanRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } } // Dump all active ScanRecords if (dumpState->args[0] == DumpStateOrd::TcDumpAllActiveScanRec){ Uint32 recordNo = 0; if (signal->getLength() == 1) infoEvent("TC: Dump active ScanRecord - size: %d", cscanrecFileSize); else if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; ScanRecordPtr sp; sp.i = recordNo; ptrAss(sp, scanRecord); if (sp.p->scanState != ScanRecord::IDLE){ dumpState->args[0] = DumpStateOrd::TcDumpOneScanRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); } if (recordNo < cscanrecFileSize-1){ dumpState->args[0] = DumpStateOrd::TcDumpAllActiveScanRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } } // Dump one ScanRecord // and associated ScanFragRec and ApiConnectRecord if (dumpState->args[0] == DumpStateOrd::TcDumpOneScanRec){ Uint32 recordNo = RNIL; if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; if (recordNo >= cscanrecFileSize) return; ScanRecordPtr sp; sp.i = recordNo; ptrAss(sp, scanRecord); infoEvent("Dbtc::ScanRecord[%d]: state=%d" "nextfrag=%d, nofrag=%d", sp.i, sp.p->scanState, sp.p->scanNextFragId, sp.p->scanNoFrag); infoEvent(" ailen=%d, para=%d, receivedop=%d, noOprePperFrag=%d", sp.p->scanAiLength, sp.p->scanParallel, sp.p->scanReceivedOperations, sp.p->batch_size_rows); infoEvent(" schv=%d, tab=%d, sproc=%d", sp.p->scanSchemaVersion, sp.p->scanTableref, sp.p->scanStoredProcId); infoEvent(" apiRec=%d, next=%d", sp.p->scanApiRec, sp.p->nextScan); if (sp.p->scanState != ScanRecord::IDLE){ // Request dump of ScanFragRec ScanFragRecPtr sfptr; #define DUMP_SFR(x){\ ScanFragList list(c_scan_frag_pool, x);\ for(list.first(sfptr); !sfptr.isNull(); list.next(sfptr)){\ dumpState->args[0] = DumpStateOrd::TcDumpOneScanFragRec; \ dumpState->args[1] = sfptr.i;\ execDUMP_STATE_ORD(signal);\ }} DUMP_SFR(sp.p->m_running_scan_frags); DUMP_SFR(sp.p->m_queued_scan_frags); DUMP_SFR(sp.p->m_delivered_scan_frags); // Request dump of ApiConnectRecord dumpState->args[0] = DumpStateOrd::TcDumpOneApiConnectRec; dumpState->args[1] = sp.p->scanApiRec; execDUMP_STATE_ORD(signal); } } // Dump all ApiConnectRecord(s) if (dumpState->args[0] == DumpStateOrd::TcDumpAllApiConnectRec){ Uint32 recordNo = 0; if (signal->getLength() == 1) infoEvent("TC: Dump all ApiConnectRecord - size: %d", capiConnectFilesize); else if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; dumpState->args[0] = DumpStateOrd::TcDumpOneApiConnectRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); if (recordNo < capiConnectFilesize-1){ dumpState->args[0] = DumpStateOrd::TcDumpAllApiConnectRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } } // Dump one ApiConnectRecord if (dumpState->args[0] == DumpStateOrd::TcDumpOneApiConnectRec){ Uint32 recordNo = RNIL; if (signal->getLength() == 2) recordNo = dumpState->args[1]; else return; if (recordNo >= capiConnectFilesize) return; ApiConnectRecordPtr ap; ap.i = recordNo; ptrAss(ap, apiConnectRecord); infoEvent("Dbtc::ApiConnectRecord[%d]: state=%d, abortState=%d, " "apiFailState=%d", ap.i, ap.p->apiConnectstate, ap.p->abortState, ap.p->apiFailState); infoEvent(" transid(0x%x, 0x%x), apiBref=0x%x, scanRec=%d", ap.p->transid[0], ap.p->transid[1], ap.p->ndbapiBlockref, ap.p->apiScanRec); infoEvent(" ctcTimer=%d, apiTimer=%d, counter=%d, retcode=%d, " "retsig=%d", ctcTimer, getApiConTimer(ap.i), ap.p->counter, ap.p->returncode, ap.p->returnsignal); infoEvent(" lqhkeyconfrec=%d, lqhkeyreqrec=%d, " "tckeyrec=%d", ap.p->lqhkeyconfrec, ap.p->lqhkeyreqrec, ap.p->tckeyrec); infoEvent(" next=%d ", ap.p->nextApiConnect); } if (dumpState->args[0] == DumpStateOrd::TcSetTransactionTimeout){ jam(); if(signal->getLength() > 1){ set_timeout_value(signal->theData[1]); } } if (dumpState->args[0] == DumpStateOrd::TcSetApplTransactionTimeout){ jam(); if(signal->getLength() > 1){ set_appl_timeout_value(signal->theData[1]); } } if (dumpState->args[0] == DumpStateOrd::StartTcTimer){ c_counters.c_trans_status = TransCounters::Started; c_counters.reset(); } if (dumpState->args[0] == DumpStateOrd::StopTcTimer){ c_counters.c_trans_status = TransCounters::Off; Uint32 len = c_counters.report(signal); sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, len, JBB); c_counters.reset(); } if (dumpState->args[0] == DumpStateOrd::StartPeriodicTcTimer){ c_counters.c_trans_status = TransCounters::Timer; c_counters.reset(); signal->theData[0] = TcContinueB::ZTRANS_EVENT_REP; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 1); } if (dumpState->args[0] == DumpStateOrd::TcStartDumpIndexOpCount) { static int frequency = 1; if (signal->getLength() > 1) frequency = signal->theData[1]; else if (refToBlock(signal->getSendersBlockRef()) != DBTC) frequency = 1; if (frequency) { dumpState->args[0] = DumpStateOrd::TcDumpIndexOpCount; execDUMP_STATE_ORD(signal); dumpState->args[0] = DumpStateOrd::TcStartDumpIndexOpCount; Uint32 delay = 1000 * (frequency > 25 ? 25 : frequency); sendSignalWithDelay(cownref, GSN_DUMP_STATE_ORD, signal, delay, 1); } } if (dumpState->args[0] == DumpStateOrd::TcDumpIndexOpCount) { infoEvent("IndexOpCount: pool: %d free: %d", c_theIndexOperationPool.getSize(), c_theIndexOperationPool.getNoOfFree()); } if (dumpState->args[0] == 2514) { if (signal->getLength() == 2) { dumpState->args[0] = DumpStateOrd::TcDumpOneApiConnectRec; execDUMP_STATE_ORD(signal); } NodeReceiverGroup rg(CMVMI, c_alive_nodes); dumpState->args[0] = 15; sendSignal(rg, GSN_DUMP_STATE_ORD, signal, 1, JBB); signal->theData[0] = 2515; sendSignalWithDelay(cownref, GSN_DUMP_STATE_ORD, signal, 1000, 1); return; } if (dumpState->args[0] == 2515) { NdbNodeBitmask mask = c_alive_nodes; mask.clear(getOwnNodeId()); NodeReceiverGroup rg(NDBCNTR, mask); sendSignal(rg, GSN_SYSTEM_ERROR, signal, 1, JBB); sendSignalWithDelay(cownref, GSN_SYSTEM_ERROR, signal, 300, 1); return; } }//Dbtc::execDUMP_STATE_ORD() void Dbtc::execABORT_ALL_REQ(Signal* signal) { jamEntry(); AbortAllReq * req = (AbortAllReq*)&signal->theData[0]; AbortAllRef * ref = (AbortAllRef*)&signal->theData[0]; const Uint32 senderData = req->senderData; const BlockReference senderRef = req->senderRef; if(getAllowStartTransaction(refToNode(senderRef), 0) == true && !getNodeState().getSingleUserMode()){ jam(); ref->senderData = senderData; ref->errorCode = AbortAllRef::InvalidState; sendSignal(senderRef, GSN_ABORT_ALL_REF, signal, AbortAllRef::SignalLength, JBB); return; } if(c_abortRec.clientRef != 0){ jam(); ref->senderData = senderData; ref->errorCode = AbortAllRef::AbortAlreadyInProgress; sendSignal(senderRef, GSN_ABORT_ALL_REF, signal, AbortAllRef::SignalLength, JBB); return; } if(refToNode(senderRef) != getOwnNodeId()){ jam(); ref->senderData = senderData; ref->errorCode = AbortAllRef::FunctionNotImplemented; sendSignal(senderRef, GSN_ABORT_ALL_REF, signal, AbortAllRef::SignalLength, JBB); return; } c_abortRec.clientRef = senderRef; c_abortRec.clientData = senderData; c_abortRec.oldTimeOutValue = ctimeOutValue; ctimeOutValue = 0; const Uint32 sleepTime = (2 * 10 * ctimeOutCheckDelay + 199) / 200; checkAbortAllTimeout(signal, (sleepTime == 0 ? 1 : sleepTime)); } void Dbtc::checkAbortAllTimeout(Signal* signal, Uint32 sleepTime) { ndbrequire(c_abortRec.clientRef != 0); if(sleepTime > 0){ jam(); sleepTime -= 1; signal->theData[0] = TcContinueB::ZWAIT_ABORT_ALL; signal->theData[1] = sleepTime; sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 200, 2); return; } AbortAllConf * conf = (AbortAllConf*)&signal->theData[0]; conf->senderData = c_abortRec.clientData; sendSignal(c_abortRec.clientRef, GSN_ABORT_ALL_CONF, signal, AbortAllConf::SignalLength, JBB); ctimeOutValue = c_abortRec.oldTimeOutValue; c_abortRec.clientRef = 0; } /* **************************************************************** */ /* ---------------------------------------------------------------- */ /* ------------------ TRIGGER AND INDEX HANDLING ------------------ */ /* ---------------------------------------------------------------- */ /* **************************************************************** */ void Dbtc::execCREATE_TRIG_REQ(Signal* signal) { jamEntry(); CreateTrigReq * const createTrigReq = (CreateTrigReq *)&signal->theData[0]; TcDefinedTriggerData* triggerData; DefinedTriggerPtr triggerPtr; BlockReference sender = signal->senderBlockRef(); releaseSections(signal); triggerPtr.i = createTrigReq->getTriggerId(); if (ERROR_INSERTED(8033) || !c_theDefinedTriggers.seizeId(triggerPtr, createTrigReq->getTriggerId())) { jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate trigger record CreateTrigRef * const createTrigRef = (CreateTrigRef *)&signal->theData[0]; createTrigRef->setConnectionPtr(createTrigReq->getConnectionPtr()); createTrigRef->setErrorCode(CreateTrigRef::TooManyTriggers); sendSignal(sender, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB); return; } triggerData = triggerPtr.p; triggerData->triggerId = createTrigReq->getTriggerId(); triggerData->triggerType = createTrigReq->getTriggerType(); triggerData->triggerEvent = createTrigReq->getTriggerEvent(); triggerData->attributeMask = createTrigReq->getAttributeMask(); if (triggerData->triggerType == TriggerType::SECONDARY_INDEX) triggerData->indexId = createTrigReq->getIndexId(); CreateTrigConf * const createTrigConf = (CreateTrigConf *)&signal->theData[0]; createTrigConf->setConnectionPtr(createTrigReq->getConnectionPtr()); sendSignal(sender, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB); } void Dbtc::execDROP_TRIG_REQ(Signal* signal) { jamEntry(); DropTrigReq * const dropTrigReq = (DropTrigReq *)&signal->theData[0]; BlockReference sender = signal->senderBlockRef(); if (ERROR_INSERTED(8035) || (c_theDefinedTriggers.getPtr(dropTrigReq->getTriggerId())) == NULL) { jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to find find trigger record DropTrigRef * const dropTrigRef = (DropTrigRef *)&signal->theData[0]; dropTrigRef->setConnectionPtr(dropTrigReq->getConnectionPtr()); dropTrigRef->setErrorCode(DropTrigRef::TriggerNotFound); sendSignal(sender, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB); return; } // Release trigger record c_theDefinedTriggers.release(dropTrigReq->getTriggerId()); DropTrigConf * const dropTrigConf = (DropTrigConf *)&signal->theData[0]; dropTrigConf->setConnectionPtr(dropTrigReq->getConnectionPtr()); sendSignal(sender, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB); } void Dbtc::execCREATE_INDX_REQ(Signal* signal) { jamEntry(); CreateIndxReq * const createIndxReq = (CreateIndxReq *)signal->getDataPtr(); TcIndexData* indexData; TcIndexDataPtr indexPtr; BlockReference sender = signal->senderBlockRef(); if (ERROR_INSERTED(8034) || !c_theIndexes.seizeId(indexPtr, createIndxReq->getIndexId())) { jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate index record CreateIndxRef * const createIndxRef = (CreateIndxRef *)&signal->theData[0]; createIndxRef->setConnectionPtr(createIndxReq->getConnectionPtr()); createIndxRef->setErrorCode(CreateIndxRef::TooManyIndexes); releaseSections(signal); sendSignal(sender, GSN_CREATE_INDX_REF, signal, CreateIndxRef::SignalLength, JBB); return; } indexData = indexPtr.p; // Indexes always start in state IS_BUILDING // Will become IS_ONLINE in execALTER_INDX_REQ indexData->indexState = IS_BUILDING; indexData->indexId = indexPtr.i; indexData->primaryTableId = createIndxReq->getTableId(); // So far need only attribute count SegmentedSectionPtr ssPtr; signal->getSection(ssPtr, CreateIndxReq::ATTRIBUTE_LIST_SECTION); SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); r0.reset(); // undo implicit first() if (!r0.getWord(&indexData->attributeList.sz) || !r0.getWords(indexData->attributeList.id, indexData->attributeList.sz)) { ndbrequire(false); } indexData->primaryKeyPos = indexData->attributeList.sz; releaseSections(signal); CreateIndxConf * const createIndxConf = (CreateIndxConf *)&signal->theData[0]; createIndxConf->setConnectionPtr(createIndxReq->getConnectionPtr()); createIndxConf->setTableId(createIndxReq->getTableId()); createIndxConf->setIndexId(createIndxReq->getIndexId()); sendSignal(sender, GSN_CREATE_INDX_CONF, signal, CreateIndxConf::SignalLength, JBB); } void Dbtc::execALTER_INDX_REQ(Signal* signal) { jamEntry(); AlterIndxReq * const alterIndxReq = (AlterIndxReq *)signal->getDataPtr(); TcIndexData* indexData; //BlockReference sender = signal->senderBlockRef(); BlockReference sender = (BlockReference) alterIndxReq->getUserRef(); Uint32 connectionPtr = alterIndxReq->getConnectionPtr(); AlterIndxReq::RequestType requestType = alterIndxReq->getRequestType(); Uint32 tableId = alterIndxReq->getTableId(); Uint32 indexId = alterIndxReq->getIndexId(); bool online = (alterIndxReq->getOnline() == 1) ? true : false; if ((indexData = c_theIndexes.getPtr(indexId)) == NULL) { jam(); // Failed to find index record AlterIndxRef * const alterIndxRef = (AlterIndxRef *)signal->getDataPtrSend(); alterIndxRef->setUserRef(reference()); alterIndxRef->setConnectionPtr(connectionPtr); alterIndxRef->setRequestType(requestType); alterIndxRef->setTableId(tableId); alterIndxRef->setIndexId(indexId); alterIndxRef->setErrorCode(AlterIndxRef::IndexNotFound); alterIndxRef->setErrorLine(__LINE__); alterIndxRef->setErrorNode(getOwnNodeId()); sendSignal(sender, GSN_ALTER_INDX_REF, signal, AlterIndxRef::SignalLength, JBB); return; } // Found index record, alter it's state if (online) { jam(); indexData->indexState = IS_ONLINE; } else { jam(); indexData->indexState = IS_BUILDING; }//if AlterIndxConf * const alterIndxConf = (AlterIndxConf *)signal->getDataPtrSend(); alterIndxConf->setUserRef(reference()); alterIndxConf->setConnectionPtr(connectionPtr); alterIndxConf->setRequestType(requestType); alterIndxConf->setTableId(tableId); alterIndxConf->setIndexId(indexId); sendSignal(sender, GSN_ALTER_INDX_CONF, signal, AlterIndxConf::SignalLength, JBB); } void Dbtc::execFIRE_TRIG_ORD(Signal* signal) { jamEntry(); FireTrigOrd * const fireOrd = (FireTrigOrd *)signal->getDataPtr(); ApiConnectRecord *localApiConnectRecord = apiConnectRecord; ApiConnectRecordPtr transPtr; TcConnectRecord *localTcConnectRecord = tcConnectRecord; TcConnectRecordPtr opPtr; /** * TODO * Check transid, * Fix overload i.e invalid word count */ TcFiredTriggerData key; key.fireingOperation = fireOrd->getConnectionPtr(); key.nodeId = refToNode(signal->getSendersBlockRef()); FiredTriggerPtr trigPtr; if(c_firedTriggerHash.find(trigPtr, key)){ c_firedTriggerHash.remove(trigPtr); trigPtr.p->fragId= fireOrd->fragId; bool ok = trigPtr.p->keyValues.getSize() == fireOrd->m_noPrimKeyWords; ok &= trigPtr.p->afterValues.getSize() == fireOrd->m_noAfterValueWords; ok &= trigPtr.p->beforeValues.getSize() == fireOrd->m_noBeforeValueWords; if(ok){ opPtr.i = key.fireingOperation; ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord); transPtr.i = opPtr.p->apiConnect; transPtr.p = &localApiConnectRecord[transPtr.i]; opPtr.p->noReceivedTriggers++; opPtr.p->triggerExecutionCount++; // Insert fired trigger in execution queue transPtr.p->theFiredTriggers.add(trigPtr); if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers) { executeTriggers(signal, &transPtr); } return; } jam(); c_theFiredTriggerPool.release(trigPtr); } jam(); /** * Failed to find record or invalid word counts */ ndbrequire(false); } void Dbtc::execTRIG_ATTRINFO(Signal* signal) { jamEntry(); TrigAttrInfo * const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtr(); Uint32 attrInfoLength = signal->getLength() - TrigAttrInfo::StaticLength; const Uint32 *src = trigAttrInfo->getData(); FiredTriggerPtr firedTrigPtr; TcFiredTriggerData key; key.fireingOperation = trigAttrInfo->getConnectionPtr(); key.nodeId = refToNode(signal->getSendersBlockRef()); if(!c_firedTriggerHash.find(firedTrigPtr, key)){ jam(); if(!c_firedTriggerHash.seize(firedTrigPtr)){ jam(); /** * Will be handled when FIRE_TRIG_ORD arrives */ ndbout_c("op: %d node: %d failed to seize", key.fireingOperation, key.nodeId); return; } ndbrequire(firedTrigPtr.p->keyValues.getSize() == 0 && firedTrigPtr.p->beforeValues.getSize() == 0 && firedTrigPtr.p->afterValues.getSize() == 0); firedTrigPtr.p->nodeId = refToNode(signal->getSendersBlockRef()); firedTrigPtr.p->fireingOperation = key.fireingOperation; firedTrigPtr.p->triggerId = trigAttrInfo->getTriggerId(); c_firedTriggerHash.add(firedTrigPtr); } AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool; switch (trigAttrInfo->getAttrInfoType()) { case(TrigAttrInfo::PRIMARY_KEY): jam(); { LocalDataBuffer<11> buf(pool, firedTrigPtr.p->keyValues); buf.append(src, attrInfoLength); } break; case(TrigAttrInfo::BEFORE_VALUES): jam(); { LocalDataBuffer<11> buf(pool, firedTrigPtr.p->beforeValues); buf.append(src, attrInfoLength); } break; case(TrigAttrInfo::AFTER_VALUES): jam(); { LocalDataBuffer<11> buf(pool, firedTrigPtr.p->afterValues); buf.append(src, attrInfoLength); } break; default: ndbrequire(false); } } void Dbtc::execDROP_INDX_REQ(Signal* signal) { jamEntry(); DropIndxReq * const dropIndxReq = (DropIndxReq *)signal->getDataPtr(); TcIndexData* indexData; BlockReference sender = signal->senderBlockRef(); if (ERROR_INSERTED(8036) || (indexData = c_theIndexes.getPtr(dropIndxReq->getIndexId())) == NULL) { jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to find index record DropIndxRef * const dropIndxRef = (DropIndxRef *)signal->getDataPtrSend(); dropIndxRef->setConnectionPtr(dropIndxReq->getConnectionPtr()); dropIndxRef->setErrorCode(DropIndxRef::IndexNotFound); sendSignal(sender, GSN_DROP_INDX_REF, signal, DropIndxRef::SignalLength, JBB); return; } // Release index record c_theIndexes.release(dropIndxReq->getIndexId()); DropIndxConf * const dropIndxConf = (DropIndxConf *)signal->getDataPtrSend(); dropIndxConf->setConnectionPtr(dropIndxReq->getConnectionPtr()); sendSignal(sender, GSN_DROP_INDX_CONF, signal, DropIndxConf::SignalLength, JBB); } void Dbtc::execTCINDXREQ(Signal* signal) { jamEntry(); TcKeyReq * const tcIndxReq = (TcKeyReq *)signal->getDataPtr(); const UintR TapiIndex = tcIndxReq->apiConnectPtr; Uint32 tcIndxRequestInfo = tcIndxReq->requestInfo; Uint32 startFlag = tcIndxReq->getStartFlag(tcIndxRequestInfo); Uint32 * dataPtr = &tcIndxReq->scanInfo; Uint32 indexBufSize = 8; // Maximum for index in TCINDXREQ Uint32 attrBufSize = 5; // Maximum for attrInfo in TCINDXREQ ApiConnectRecordPtr transPtr; transPtr.i = TapiIndex; if (transPtr.i >= capiConnectFilesize) { jam(); warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); ApiConnectRecord * const regApiPtr = transPtr.p; // Seize index operation TcIndexOperationPtr indexOpPtr; if ((startFlag == 1) && (regApiPtr->apiConnectstate == CS_CONNECTED || (regApiPtr->apiConnectstate == CS_STARTED && regApiPtr->firstTcConnect == RNIL)) || (regApiPtr->apiConnectstate == CS_ABORTING && regApiPtr->abortState == AS_IDLE)) { jam(); // This is a newly started transaction, clean-up releaseAllSeizedIndexOperations(regApiPtr); regApiPtr->apiConnectstate = CS_STARTED; regApiPtr->transid[0] = tcIndxReq->transId1; regApiPtr->transid[1] = tcIndxReq->transId2; }//if if (getNodeState().startLevel == NodeState::SL_SINGLEUSER && getNodeState().getSingleUserApi() != refToNode(regApiPtr->ndbapiBlockref)) { terrorCode = ZCLUSTER_IN_SINGLEUSER_MODE; regApiPtr->m_exec_flag |= TcKeyReq::getExecuteFlag(tcIndxRequestInfo); apiConnectptr = transPtr; abortErrorLab(signal); return; } if (ERROR_INSERTED(8036) || !seizeIndexOperation(regApiPtr, indexOpPtr)) { jam(); // Failed to allocate index operation terrorCode = 288; regApiPtr->m_exec_flag |= TcKeyReq::getExecuteFlag(tcIndxRequestInfo); apiConnectptr = transPtr; abortErrorLab(signal); return; } TcIndexOperation* indexOp = indexOpPtr.p; indexOp->indexOpId = indexOpPtr.i; // Save original signal indexOp->tcIndxReq = *tcIndxReq; indexOp->connectionIndex = TapiIndex; regApiPtr->accumulatingIndexOp = indexOp->indexOpId; // If operation is readTupleExclusive or updateTuple then read index // table with exclusive lock Uint32 indexLength = TcKeyReq::getKeyLength(tcIndxRequestInfo); Uint32 attrLength = TcKeyReq::getAttrinfoLen(tcIndxReq->attrLen); indexOp->expectedKeyInfo = indexLength; Uint32 includedIndexLength = MIN(indexLength, indexBufSize); indexOp->expectedAttrInfo = attrLength; Uint32 includedAttrLength = MIN(attrLength, attrBufSize); int ret; if ((ret = saveINDXKEYINFO(signal, indexOp, dataPtr, includedIndexLength)) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); return; } else if (ret == -1) { jam(); return; } dataPtr += includedIndexLength; if (saveINDXATTRINFO(signal, indexOp, dataPtr, includedAttrLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); return; } } void Dbtc::sendTcIndxConf(Signal* signal, UintR TcommitFlag) { HostRecordPtr localHostptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; const UintR TopWords = (UintR)regApiPtr->tcindxrec; localHostptr.i = refToNode(regApiPtr->ndbapiBlockref); const Uint32 type = getNodeInfo(localHostptr.i).m_type; const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::MGM); const BlockNumber TblockNum = refToBlock(regApiPtr->ndbapiBlockref); const Uint32 Tmarker = (regApiPtr->commitAckMarker == RNIL ? 0 : 1); ptrAss(localHostptr, hostRecord); UintR TcurrLen = localHostptr.p->noOfWordsTCINDXCONF; UintR confInfo = 0; TcIndxConf::setNoOfOperations(confInfo, (TopWords >> 1)); TcIndxConf::setCommitFlag(confInfo, TcommitFlag == 1); TcIndxConf::setMarkerFlag(confInfo, Tmarker); const UintR TpacketLen = 6 + TopWords; regApiPtr->tcindxrec = 0; if(TcommitFlag || (regApiPtr->lqhkeyreqrec == regApiPtr->lqhkeyconfrec)){ jam(); regApiPtr->m_exec_flag = 0; } if ((TpacketLen > 25) || !is_api){ TcIndxConf * const tcIndxConf = (TcIndxConf *)signal->getDataPtrSend(); jam(); tcIndxConf->apiConnectPtr = regApiPtr->ndbapiConnect; tcIndxConf->gci = regApiPtr->globalcheckpointid;; tcIndxConf->confInfo = confInfo; tcIndxConf->transId1 = regApiPtr->transid[0]; tcIndxConf->transId2 = regApiPtr->transid[1]; copyFromToLen(®ApiPtr->tcIndxSendArray[0], (UintR*)&tcIndxConf->operations, (UintR)ZTCOPCONF_SIZE); sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXCONF, signal, (TpacketLen - 1), JBB); return; } else if (((TcurrLen + TpacketLen) > 25) && (TcurrLen > 0)) { jam(); sendPackedTCINDXCONF(signal, localHostptr.p, localHostptr.i); TcurrLen = 0; } else { jam(); updatePackedList(signal, localHostptr.p, localHostptr.i); }//if // ------------------------------------------------------------------------- // The header contains the block reference of receiver plus the real signal // length - 3, since we have the real signal length plus one additional word // for the header we have to do - 4. // ------------------------------------------------------------------------- UintR Tpack0 = (TblockNum << 16) + (TpacketLen - 4); UintR Tpack1 = regApiPtr->ndbapiConnect; UintR Tpack2 = regApiPtr->globalcheckpointid; UintR Tpack3 = confInfo; UintR Tpack4 = regApiPtr->transid[0]; UintR Tpack5 = regApiPtr->transid[1]; localHostptr.p->noOfWordsTCINDXCONF = TcurrLen + TpacketLen; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 0] = Tpack0; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 1] = Tpack1; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 2] = Tpack2; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 3] = Tpack3; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 4] = Tpack4; localHostptr.p->packedWordsTCINDXCONF[TcurrLen + 5] = Tpack5; UintR Ti; for (Ti = 6; Ti < TpacketLen; Ti++) { localHostptr.p->packedWordsTCINDXCONF[TcurrLen + Ti] = regApiPtr->tcIndxSendArray[Ti - 6]; }//for }//Dbtc::sendTcIndxConf() void Dbtc::execINDXKEYINFO(Signal* signal) { jamEntry(); Uint32 keyInfoLength = signal->getLength() - IndxKeyInfo::HeaderLength; IndxKeyInfo * const indxKeyInfo = (IndxKeyInfo *)signal->getDataPtr(); const Uint32 *src = indxKeyInfo->getData(); const UintR TconnectIndex = indxKeyInfo->connectPtr; ApiConnectRecordPtr transPtr; transPtr.i = TconnectIndex; if (transPtr.i >= capiConnectFilesize) { jam(); warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); ApiConnectRecord * const regApiPtr = transPtr.p; TcIndexOperationPtr indexOpPtr; TcIndexOperation* indexOp; if (compare_transid(regApiPtr->transid, indxKeyInfo->transId) == false) { TCKEY_abort(signal, 19); return; } if (regApiPtr->apiConnectstate == CS_ABORTING) { jam(); return; } if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) { indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); if (saveINDXKEYINFO(signal, indexOp, src, keyInfoLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); } } } void Dbtc::execINDXATTRINFO(Signal* signal) { jamEntry(); Uint32 attrInfoLength = signal->getLength() - IndxAttrInfo::HeaderLength; IndxAttrInfo * const indxAttrInfo = (IndxAttrInfo *)signal->getDataPtr(); const Uint32 *src = indxAttrInfo->getData(); const UintR TconnectIndex = indxAttrInfo->connectPtr; ApiConnectRecordPtr transPtr; transPtr.i = TconnectIndex; if (transPtr.i >= capiConnectFilesize) { jam(); warningHandlerLab(signal, __LINE__); return; }//if ptrAss(transPtr, apiConnectRecord); ApiConnectRecord * const regApiPtr = transPtr.p; TcIndexOperationPtr indexOpPtr; TcIndexOperation* indexOp; if (compare_transid(regApiPtr->transid, indxAttrInfo->transId) == false) { TCKEY_abort(signal, 19); return; } if (regApiPtr->apiConnectstate == CS_ABORTING) { jam(); return; } if((indexOpPtr.i = regApiPtr->accumulatingIndexOp) != RNIL) { indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); if (saveINDXATTRINFO(signal, indexOp, src, attrInfoLength) == 0) { jam(); // We have received all we need readIndexTable(signal, regApiPtr, indexOp); return; } return; } } /** * Save signal INDXKEYINFO * Return true if we have received all needed data */ int Dbtc::saveINDXKEYINFO(Signal* signal, TcIndexOperation* indexOp, const Uint32 *src, Uint32 len) { if (ERROR_INSERTED(8052) || !indexOp->keyInfo.append(src, len)) { jam(); // Failed to seize keyInfo, abort transaction #ifdef VM_TRACE ndbout_c("Dbtc::saveINDXKEYINFO: Failed to seize keyinfo\n"); #endif // Abort transaction apiConnectptr.i = indexOp->connectionIndex; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); releaseIndexOperation(apiConnectptr.p, indexOp); terrorCode = 289; if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo)) apiConnectptr.p->m_exec_flag= 1; abortErrorLab(signal); return -1; } if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { jam(); return 0; } return 1; } bool Dbtc::receivedAllINDXKEYINFO(TcIndexOperation* indexOp) { return (indexOp->keyInfo.getSize() == indexOp->expectedKeyInfo); } /** * Save signal INDXATTRINFO * Return true if we have received all needed data */ int Dbtc::saveINDXATTRINFO(Signal* signal, TcIndexOperation* indexOp, const Uint32 *src, Uint32 len) { if (ERROR_INSERTED(8051) || !indexOp->attrInfo.append(src, len)) { jam(); #ifdef VM_TRACE ndbout_c("Dbtc::saveINDXATTRINFO: Failed to seize attrInfo\n"); #endif apiConnectptr.i = indexOp->connectionIndex; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); releaseIndexOperation(apiConnectptr.p, indexOp); terrorCode = 289; if(TcKeyReq::getExecuteFlag(indexOp->tcIndxReq.requestInfo)) apiConnectptr.p->m_exec_flag= 1; abortErrorLab(signal); return -1; } if (receivedAllINDXKEYINFO(indexOp) && receivedAllINDXATTRINFO(indexOp)) { jam(); return 0; } return 1; } bool Dbtc::receivedAllINDXATTRINFO(TcIndexOperation* indexOp) { return (indexOp->attrInfo.getSize() == indexOp->expectedAttrInfo); } bool Dbtc::saveTRANSID_AI(Signal* signal, TcIndexOperation* indexOp, const Uint32 *src, Uint32 len) { Uint32 currentTransIdAILength = indexOp->transIdAI.getSize(); if (currentTransIdAILength == 0) { jam(); // Read first AttributeHeader to get expected size // of the single key attribute expected AttributeHeader* head = (AttributeHeader *) src; indexOp->expectedTransIdAI = head->getHeaderSize() + head->getDataSize(); } if (!indexOp->transIdAI.append(src, len)) { jam(); #ifdef VM_TRACE ndbout_c("Dbtc::saveTRANSID_AI: Failed to seize transIdAI\n"); #endif apiConnectptr.i = indexOp->connectionIndex; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); releaseIndexOperation(apiConnectptr.p, indexOp); terrorCode = 4000; abortErrorLab(signal); return false; } return true; } bool Dbtc::receivedAllTRANSID_AI(TcIndexOperation* indexOp) { return (indexOp->transIdAI.getSize() == indexOp->expectedTransIdAI); } /** * Receive signal TCINDXCONF * This can be either the return of reading an index table * or performing an index operation */ void Dbtc::execTCKEYCONF(Signal* signal) { TcKeyConf * const tcKeyConf = (TcKeyConf *)signal->getDataPtr(); TcIndexOperationPtr indexOpPtr; jamEntry(); indexOpPtr.i = tcKeyConf->apiConnectPtr; TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); Uint32 confInfo = tcKeyConf->confInfo; /** * Check on TCKEYCONF wheater the the transaction was committed */ Uint32 Tcommit = TcKeyConf::getCommitFlag(confInfo); indexOpPtr.p = indexOp; if (!indexOp) { jam(); // Missing index operation return; } const UintR TconnectIndex = indexOp->connectionIndex; ApiConnectRecord * const regApiPtr = &apiConnectRecord[TconnectIndex]; apiConnectptr.p = regApiPtr; apiConnectptr.i = TconnectIndex; switch(indexOp->indexOpState) { case(IOS_NOOP): { jam(); // Should never happen, abort TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } case(IOS_INDEX_ACCESS): { jam(); // Wait for TRANSID_AI indexOp->indexOpState = IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI; break; } case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): { jam(); // Double TCKEYCONF, should never happen, abort TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): { jam(); // Continue with index operation executeIndexOperation(signal, regApiPtr, indexOp); break; } case(IOS_INDEX_OPERATION): { // We are done, send TCINDXCONF jam(); Uint32 Ttcindxrec = regApiPtr->tcindxrec; // Copy reply from TcKeyConf ndbassert(regApiPtr->noIndexOp); regApiPtr->noIndexOp--; // Decrease count regApiPtr->tcIndxSendArray[Ttcindxrec] = indexOp->tcIndxReq.senderData; regApiPtr->tcIndxSendArray[Ttcindxrec + 1] = tcKeyConf->operations[0].attrInfoLen; regApiPtr->tcindxrec = Ttcindxrec + 2; if (regApiPtr->noIndexOp == 0) { jam(); sendTcIndxConf(signal, Tcommit); } else if (regApiPtr->tcindxrec == ZTCOPCONF_SIZE) { jam(); sendTcIndxConf(signal, 0); } releaseIndexOperation(regApiPtr, indexOp); break; } } } void Dbtc::execTCKEYREF(Signal* signal) { TcKeyRef * const tcKeyRef = (TcKeyRef *)signal->getDataPtr(); TcIndexOperationPtr indexOpPtr; jamEntry(); indexOpPtr.i = tcKeyRef->connectPtr; TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); indexOpPtr.p = indexOp; if (!indexOp) { jam(); // Missing index operation return; } const UintR TconnectIndex = indexOp->connectionIndex; ApiConnectRecord * const regApiPtr = &apiConnectRecord[TconnectIndex]; switch(indexOp->indexOpState) { case(IOS_NOOP): { jam(); // Should never happen, abort break; } case(IOS_INDEX_ACCESS): case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): { jam(); /** * Increase count as it will be decreased below... * (and the code is written to handle failing lookup on "real" table * not lookup on index table) */ regApiPtr->noIndexOp++; // else continue } case(IOS_INDEX_OPERATION): { // Send TCINDXREF jam(); TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq; TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); ndbassert(regApiPtr->noIndexOp); regApiPtr->noIndexOp--; // Decrease count tcIndxRef->connectPtr = tcIndxReq->senderData; tcIndxRef->transId[0] = tcKeyRef->transId[0]; tcIndxRef->transId[1] = tcKeyRef->transId[1]; tcIndxRef->errorCode = tcKeyRef->errorCode; tcIndxRef->errorData = 0; releaseIndexOperation(regApiPtr, indexOp); sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } } } void Dbtc::execTRANSID_AI_R(Signal* signal){ TransIdAI * const transIdAI = (TransIdAI *)signal->getDataPtr(); Uint32 sigLen = signal->length(); Uint32 dataLen = sigLen - TransIdAI::HeaderLength - 1; Uint32 recBlockref = transIdAI->attrData[dataLen]; jamEntry(); /** * Forward signal to final destination * Truncate last word since that was used to hold the final dest. */ sendSignal(recBlockref, GSN_TRANSID_AI, signal, sigLen - 1, JBB); } void Dbtc::execKEYINFO20_R(Signal* signal){ KeyInfo20 * const keyInfo = (KeyInfo20 *)signal->getDataPtr(); Uint32 sigLen = signal->length(); Uint32 dataLen = sigLen - KeyInfo20::HeaderLength - 1; Uint32 recBlockref = keyInfo->keyData[dataLen]; jamEntry(); /** * Forward signal to final destination * Truncate last word since that was used to hold the final dest. */ sendSignal(recBlockref, GSN_KEYINFO20, signal, sigLen - 1, JBB); } void Dbtc::execTRANSID_AI(Signal* signal) { TransIdAI * const transIdAI = (TransIdAI *)signal->getDataPtr(); jamEntry(); TcIndexOperationPtr indexOpPtr; indexOpPtr.i = transIdAI->connectPtr; TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); indexOpPtr.p = indexOp; if (!indexOp) { jam(); // Missing index operation } const UintR TconnectIndex = indexOp->connectionIndex; // ApiConnectRecord * const regApiPtr = &apiConnectRecord[TconnectIndex]; ApiConnectRecordPtr transPtr; transPtr.i = TconnectIndex; ptrCheckGuard(transPtr, capiConnectFilesize, apiConnectRecord); ApiConnectRecord * const regApiPtr = transPtr.p; // Acccumulate attribute data if (!saveTRANSID_AI(signal, indexOp, transIdAI->getData(), signal->getLength() - TransIdAI::HeaderLength)) { jam(); // Failed to allocate space for TransIdAI TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4000; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } switch(indexOp->indexOpState) { case(IOS_NOOP): { jam(); // Should never happen, abort TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; break; } case(IOS_INDEX_ACCESS): { jam(); // Check if all TRANSID_AI have been received if (receivedAllTRANSID_AI(indexOp)) { jam(); // Wait for TRANSID_AI indexOp->indexOpState = IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF; } break; } case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): { jam(); #ifdef VM_TRACE ndbout_c("Dbtc::execTRANSID_AI: Too many TRANSID_AI, ignore for now\n"); #endif /* // Too many TRANSID_AI TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndexRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); */ break; } case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): { jam(); // Check if all TRANSID_AI have been received if (receivedAllTRANSID_AI(indexOp)) { jam(); // Continue with index operation executeIndexOperation(signal, regApiPtr, indexOp); } // else continue waiting for more TRANSID_AI break; } case(IOS_INDEX_OPERATION): { // Should never receive TRANSID_AI in this state!! jam(); TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = regApiPtr->errorData; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } } } void Dbtc::execTCROLLBACKREP(Signal* signal) { TcRollbackRep* tcRollbackRep = (TcRollbackRep *)signal->getDataPtr(); jamEntry(); TcIndexOperationPtr indexOpPtr; indexOpPtr.i = tcRollbackRep->connectPtr; TcIndexOperation* indexOp = c_theIndexOperationPool.getPtr(indexOpPtr.i); indexOpPtr.p = indexOp; tcRollbackRep = (TcRollbackRep *)signal->getDataPtrSend(); tcRollbackRep->connectPtr = indexOp->tcIndxReq.senderData; sendSignal(apiConnectptr.p->ndbapiBlockref, GSN_TCROLLBACKREP, signal, TcRollbackRep::SignalLength, JBB); } /** * Read index table with the index attributes as PK */ void Dbtc::readIndexTable(Signal* signal, ApiConnectRecord* regApiPtr, TcIndexOperation* indexOp) { Uint32 keyBufSize = 8; // Maximum for key in TCKEYREQ Uint32 dataPos = 0; TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend(); Uint32 * dataPtr = &tcKeyReq->scanInfo; Uint32 tcKeyLength = TcKeyReq::StaticLength; Uint32 tcKeyRequestInfo = indexOp->tcIndxReq.requestInfo; AttributeBuffer::DataBufferIterator keyIter; Uint32 keyLength = TcKeyReq::getKeyLength(tcKeyRequestInfo); TcIndexData* indexData; Uint32 transId1 = indexOp->tcIndxReq.transId1; Uint32 transId2 = indexOp->tcIndxReq.transId2; const Operation_t opType = (Operation_t)TcKeyReq::getOperationType(tcKeyRequestInfo); // Find index table if ((indexData = c_theIndexes.getPtr(indexOp->tcIndxReq.tableId)) == NULL) { jam(); // Failed to find index record TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4000; // tcIndxRef->errorData = ??; Where to find indexId sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } tcKeyReq->transId1 = transId1; tcKeyReq->transId2 = transId2; tcKeyReq->tableId = indexData->indexId; tcKeyLength += MIN(keyLength, keyBufSize); tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.tableSchemaVersion; TcKeyReq::setOperationType(tcKeyRequestInfo, opType == ZREAD ? ZREAD : ZREAD_EX); TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 1); // Allways send one AttrInfo TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); tcKeyReq->senderData = indexOp->indexOpId; indexOp->indexOpState = IOS_INDEX_ACCESS; regApiPtr->executingIndexOp = regApiPtr->accumulatingIndexOp; regApiPtr->accumulatingIndexOp = RNIL; regApiPtr->isIndexOp = 2; if (ERROR_INSERTED(8037)) { ndbout_c("shifting index version"); tcKeyReq->tableSchemaVersion = ~(Uint32)indexOp->tcIndxReq.tableSchemaVersion; } Uint32 remainingKey = indexOp->keyInfo.getSize(); bool moreKeyData = indexOp->keyInfo.first(keyIter); // *********** KEYINFO in TCKEYREQ *********** while((dataPos < keyBufSize) && (remainingKey-- != 0)) { *dataPtr++ = *keyIter.data; dataPos++; moreKeyData = indexOp->keyInfo.next(keyIter); } // *********** ATTRINFO in TCKEYREQ *********** tcKeyReq->attrLen = 1; // Primary key is stored as one attribute AttributeHeader::init(dataPtr, indexData->primaryKeyPos, 0); tcKeyLength++; tcKeyReq->requestInfo = tcKeyRequestInfo; ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { goto err; } // *********** KEYINFO *********** if (moreKeyData) { jam(); // Send KEYINFO sequence KeyInfo * const keyInfo = (KeyInfo *)signal->getDataPtrSend(); keyInfo->connectPtr = indexOp->tcIndxReq.apiConnectPtr; keyInfo->transId[0] = transId1; keyInfo->transId[1] = transId2; dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; while(remainingKey-- != 0) {// If we have not read complete key *dataPtr++ = *keyIter.data; dataPos++; if (dataPos == KeyInfo::DataLength) { // Flush KEYINFO EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { goto err; } dataPos = 0; dataPtr = (Uint32 *) &keyInfo->keyData; } moreKeyData = indexOp->keyInfo.next(keyIter); } if (dataPos != 0) { // Flush last KEYINFO EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { goto err; } } } /** * "Fool" TC not to start commiting transaction since it always will * have one outstanding lqhkeyreq * This is later decreased when the index read is complete */ regApiPtr->lqhkeyreqrec++; /** * Remember ptr to index read operation * (used to set correct save point id on index operation later) */ indexOp->indexReadTcConnect = regApiPtr->lastTcConnect; done: return; err: jam(); goto done; } /** * Execute the index operation with the result from * the index table read as PK */ void Dbtc::executeIndexOperation(Signal* signal, ApiConnectRecord* regApiPtr, TcIndexOperation* indexOp) { Uint32 keyBufSize = 8; // Maximum for key in TCKEYREQ Uint32 attrBufSize = 5; Uint32 dataPos = 0; TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq; TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend(); /* Data points to distrGroupHashValue since scanInfo is used to send fragment id of receiving fragment */ Uint32 * dataPtr = &tcKeyReq->distrGroupHashValue; Uint32 tcKeyLength = TcKeyReq::StaticLength; Uint32 tcKeyRequestInfo = tcIndxReq->requestInfo; TcIndexData* indexData; AttributeBuffer::DataBufferIterator attrIter; AttributeBuffer::DataBufferIterator aiIter; bool moreKeyData = indexOp->transIdAI.first(aiIter); // Find index table if ((indexData = c_theIndexes.getPtr(tcIndxReq->tableId)) == NULL) { jam(); // Failed to find index record TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend(); tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData; tcIndxRef->transId[0] = regApiPtr->transid[0]; tcIndxRef->transId[1] = regApiPtr->transid[1]; tcIndxRef->errorCode = 4349; tcIndxRef->errorData = 0; sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB); return; } // Find schema version of primary table TableRecordPtr tabPtr; tabPtr.i = indexData->primaryTableId; ptrCheckGuard(tabPtr, ctabrecFilesize, tableRecord); tcKeyReq->apiConnectPtr = tcIndxReq->apiConnectPtr; tcKeyReq->attrLen = tcIndxReq->attrLen; tcKeyReq->tableId = indexData->primaryTableId; tcKeyReq->tableSchemaVersion = tabPtr.p->currentSchemaVersion; tcKeyReq->transId1 = regApiPtr->transid[0]; tcKeyReq->transId2 = regApiPtr->transid[1]; tcKeyReq->senderData = tcIndxReq->senderData; // Needed for TRANSID_AI to API indexOp->indexOpState = IOS_INDEX_OPERATION; regApiPtr->isIndexOp = 1; regApiPtr->executingIndexOp = indexOp->indexOpId;; regApiPtr->noIndexOp++; // Increase count /* Filter out AttributeHeader:s since this should not be in key. Also filter out fragment id from primary key and handle that separately by setting it as Distribution Key and set indicator. */ AttributeHeader* attrHeader = (AttributeHeader *) aiIter.data; Uint32 headerSize = attrHeader->getHeaderSize(); Uint32 keySize = attrHeader->getDataSize() - 1; TcKeyReq::setKeyLength(tcKeyRequestInfo, keySize); // Skip header if (headerSize == 1) { jam(); moreKeyData = indexOp->transIdAI.next(aiIter); } else { jam(); moreKeyData = indexOp->transIdAI.next(aiIter, headerSize - 1); }//if tcKeyReq->scanInfo = *aiIter.data; //Fragment Id moreKeyData = indexOp->transIdAI.next(aiIter); TcKeyReq::setDistributionKeyFlag(tcKeyRequestInfo, 1U); while(// If we have not read complete key (keySize != 0) && (dataPos < keyBufSize)) { *dataPtr++ = *aiIter.data; dataPos++; keySize--; moreKeyData = indexOp->transIdAI.next(aiIter); } tcKeyLength += dataPos; Uint32 attributesLength = indexOp->attrInfo.getSize(); if (attributesLength <= attrBufSize) { jam(); // ATTRINFO fits in TCKEYREQ // Pack ATTRINFO IN TCKEYREQ TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, indexOp->attrInfo.getSize()); // Insert IndxAttrInfo for(bool moreAttrData = indexOp->attrInfo.first(attrIter); moreAttrData; moreAttrData = indexOp->attrInfo.next(attrIter)) { *dataPtr++ = *attrIter.data; } tcKeyLength += attributesLength; } else { jam(); // No ATTRINFO in TCKEYREQ TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0); } TcKeyReq::setCommitFlag(tcKeyRequestInfo, 0); TcKeyReq::setExecuteFlag(tcKeyRequestInfo, 0); TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); tcKeyReq->requestInfo = tcKeyRequestInfo; ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); /** * Decrease lqhkeyreqrec to compensate for addition * during read of index table * I.e. let TC start committing when other operations has completed */ regApiPtr->lqhkeyreqrec--; /** * Fix savepoint id - * fix so that index operation has the same savepoint id * as the read of the index table (TCINDXREQ) */ TcConnectRecordPtr tmp; tmp.i = indexOp->indexReadTcConnect; ptrCheckGuard(tmp, ctcConnectFilesize, tcConnectRecord); const Uint32 currSavePointId = regApiPtr->currSavePointId; regApiPtr->currSavePointId = tmp.p->savePointId; EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } regApiPtr->currSavePointId = currSavePointId; // *********** KEYINFO *********** if (moreKeyData) { jam(); // Send KEYINFO sequence KeyInfo * const keyInfo = (KeyInfo *)signal->getDataPtrSend(); keyInfo->connectPtr = indexOp->tcIndxReq.apiConnectPtr; keyInfo->transId[0] = regApiPtr->transid[0]; keyInfo->transId[1] = regApiPtr->transid[1]; dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; // Pack any part of a key attribute that did no fit TCKEYREQ while(keySize-- != 0) {// If we have not read complete key *dataPtr++ = *aiIter.data; dataPos++; if (dataPos == KeyInfo::DataLength) { // Flush KEYINFO EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPos = 0; dataPtr = (Uint32 *) &keyInfo->keyData; } moreKeyData = indexOp->transIdAI.next(aiIter); } if (dataPos != 0) { // Flush last KEYINFO EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } } } // *********** ATTRINFO *********** if (attributesLength > attrBufSize) { jam(); // No ATTRINFO in TcKeyReq TcKeyReq::setAIInTcKeyReq(tcKeyReq->requestInfo, 0); // Send ATTRINFO sequence AttrInfo * const attrInfo = (AttrInfo *)signal->getDataPtrSend(); Uint32 attrInfoPos = 0; attrInfo->connectPtr = indexOp->tcIndxReq.apiConnectPtr; attrInfo->transId[0] = regApiPtr->transid[0]; attrInfo->transId[1] = regApiPtr->transid[1]; dataPtr = (Uint32 *) &attrInfo->attrData; // Insert attribute values (insert key values of primary table) for(bool moreAttrData = indexOp->attrInfo.first(attrIter); moreAttrData; moreAttrData = indexOp->attrInfo.next(attrIter)) { *dataPtr++ = *attrIter.data; attrInfoPos++; if (attrInfoPos == AttrInfo::DataLength) { // Flush ATTRINFO EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } attrInfoPos = 0; dataPtr = (Uint32 *) &attrInfo->attrData; } } if (attrInfoPos != 0) { // Send last ATTRINFO EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + attrInfoPos); jamEntry(); } } } bool Dbtc::seizeIndexOperation(ApiConnectRecord* regApiPtr, TcIndexOperationPtr& indexOpPtr) { if (regApiPtr->theSeizedIndexOperations.seize(indexOpPtr)) { ndbassert(indexOpPtr.p->expectedKeyInfo == 0); ndbassert(indexOpPtr.p->keyInfo.getSize() == 0); ndbassert(indexOpPtr.p->expectedAttrInfo == 0); ndbassert(indexOpPtr.p->attrInfo.getSize() == 0); ndbassert(indexOpPtr.p->expectedTransIdAI == 0); ndbassert(indexOpPtr.p->transIdAI.getSize() == 0); return true; } return false; } void Dbtc::releaseIndexOperation(ApiConnectRecord* regApiPtr, TcIndexOperation* indexOp) { indexOp->indexOpState = IOS_NOOP; indexOp->expectedKeyInfo = 0; indexOp->keyInfo.release(); indexOp->expectedAttrInfo = 0; indexOp->attrInfo.release(); indexOp->expectedTransIdAI = 0; indexOp->transIdAI.release(); regApiPtr->theSeizedIndexOperations.release(indexOp->indexOpId); } void Dbtc::releaseAllSeizedIndexOperations(ApiConnectRecord* regApiPtr) { TcIndexOperationPtr seizedIndexOpPtr; regApiPtr->theSeizedIndexOperations.first(seizedIndexOpPtr); while(seizedIndexOpPtr.i != RNIL) { jam(); TcIndexOperation* indexOp = seizedIndexOpPtr.p; indexOp->indexOpState = IOS_NOOP; indexOp->expectedKeyInfo = 0; indexOp->keyInfo.release(); indexOp->expectedAttrInfo = 0; indexOp->attrInfo.release(); indexOp->expectedTransIdAI = 0; indexOp->transIdAI.release(); regApiPtr->theSeizedIndexOperations.next(seizedIndexOpPtr); } regApiPtr->theSeizedIndexOperations.release(); } void Dbtc::saveTriggeringOpState(Signal* signal, TcConnectRecord* trigOp) { LqhKeyConf * lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); copyFromToLen((UintR*)lqhKeyConf, &trigOp->savedState[0], LqhKeyConf::SignalLength); } void Dbtc::continueTriggeringOp(Signal* signal, TcConnectRecord* trigOp) { LqhKeyConf * lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); copyFromToLen(&trigOp->savedState[0], (UintR*)lqhKeyConf, LqhKeyConf::SignalLength); lqhKeyConf->noFiredTriggers = 0; trigOp->noReceivedTriggers = 0; // All triggers executed successfully, continue operation execLQHKEYCONF(signal); } void Dbtc::scheduleFiredTrigger(ApiConnectRecordPtr* transPtr, TcConnectRecordPtr* opPtr) { // Set initial values for trigger fireing operation opPtr->p->triggerExecutionCount++; // Insert fired trigger in execution queue transPtr->p->theFiredTriggers.add(opPtr->p->accumulatingTriggerData); opPtr->p->accumulatingTriggerData.i = RNIL; opPtr->p->accumulatingTriggerData.p = NULL; } void Dbtc::executeTriggers(Signal* signal, ApiConnectRecordPtr* transPtr) { ApiConnectRecord* regApiPtr = transPtr->p; TcConnectRecord *localTcConnectRecord = tcConnectRecord; TcConnectRecordPtr opPtr; FiredTriggerPtr trigPtr; if (!regApiPtr->theFiredTriggers.isEmpty()) { jam(); if ((regApiPtr->apiConnectstate == CS_STARTED) || (regApiPtr->apiConnectstate == CS_START_COMMITTING)) { jam(); regApiPtr->theFiredTriggers.first(trigPtr); while (trigPtr.i != RNIL) { jam(); // Execute all ready triggers in parallel opPtr.i = trigPtr.p->fireingOperation; ptrCheckGuard(opPtr, ctcConnectFilesize, localTcConnectRecord); FiredTriggerPtr nextTrigPtr = trigPtr; regApiPtr->theFiredTriggers.next(nextTrigPtr); if (opPtr.p->noReceivedTriggers == opPtr.p->noFiredTriggers) { jam(); // Fireing operation is ready to have a trigger executing executeTrigger(signal, trigPtr.p, transPtr, &opPtr); // Should allow for interleaving here by sending a CONTINUEB and // return // Release trigger records AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool; LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues); tmp1.release(); LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues); tmp2.release(); LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues); tmp3.release(); regApiPtr->theFiredTriggers.release(trigPtr); } trigPtr = nextTrigPtr; } return; // No more triggers, continue transaction after last executed trigger has // reurned (in execLQHKEYCONF or execLQHKEYREF) } else { // Wait until transaction is ready to execute a trigger jam(); if (!regApiPtr->triggerPending) { jam(); regApiPtr->triggerPending = true; signal->theData[0] = TcContinueB::TRIGGER_PENDING; signal->theData[1] = transPtr->i; sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB); } // else // We are already waiting for a pending trigger (CONTINUEB) } } } void Dbtc::executeTrigger(Signal* signal, TcFiredTriggerData* firedTriggerData, ApiConnectRecordPtr* transPtr, TcConnectRecordPtr* opPtr) { TcDefinedTriggerData* definedTriggerData; if ((definedTriggerData = c_theDefinedTriggers.getPtr(firedTriggerData->triggerId)) != NULL) { switch(definedTriggerData->triggerType) { case(TriggerType::SECONDARY_INDEX): jam(); executeIndexTrigger(signal, definedTriggerData, firedTriggerData, transPtr, opPtr); break; default: ndbrequire(false); } } } void Dbtc::executeIndexTrigger(Signal* signal, TcDefinedTriggerData* definedTriggerData, TcFiredTriggerData* firedTriggerData, ApiConnectRecordPtr* transPtr, TcConnectRecordPtr* opPtr) { TcIndexData* indexData; indexData = c_theIndexes.getPtr(definedTriggerData->indexId); ndbassert(indexData != NULL); switch (definedTriggerData->triggerEvent) { case(TriggerEvent::TE_INSERT): { jam(); insertIntoIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData); break; } case(TriggerEvent::TE_DELETE): { jam(); deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData); break; } case(TriggerEvent::TE_UPDATE): { jam(); deleteFromIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData, true); // Hold the triggering operation insertIntoIndexTable(signal, firedTriggerData, transPtr, opPtr, indexData); break; } default: ndbrequire(false); } } void Dbtc::releaseFiredTriggerData(DLFifoList* triggers) { FiredTriggerPtr trigPtr; triggers->first(trigPtr); while (trigPtr.i != RNIL) { jam(); // Release trigger records AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool; LocalDataBuffer<11> tmp1(pool, trigPtr.p->keyValues); tmp1.release(); LocalDataBuffer<11> tmp2(pool, trigPtr.p->beforeValues); tmp2.release(); LocalDataBuffer<11> tmp3(pool, trigPtr.p->afterValues); tmp3.release(); triggers->next(trigPtr); } triggers->release(); } void Dbtc::insertIntoIndexTable(Signal* signal, TcFiredTriggerData* firedTriggerData, ApiConnectRecordPtr* transPtr, TcConnectRecordPtr* opPtr, TcIndexData* indexData, bool holdOperation) { ApiConnectRecord* regApiPtr = transPtr->p; TcConnectRecord* opRecord = opPtr->p; TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend(); Uint32 tcKeyRequestInfo = 0; Uint32 tcKeyLength = TcKeyReq::StaticLength; TableRecordPtr indexTabPtr; AttributeBuffer::DataBufferIterator iter; Uint32 attrId = 0; Uint32 keyLength = 0; Uint32 totalPrimaryKeyLength = 1; // fragment length Uint32 hops; indexTabPtr.i = indexData->indexId; ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord); tcKeyReq->apiConnectPtr = transPtr->i; tcKeyReq->senderData = opPtr->i; if (holdOperation) { jam(); opRecord->triggerExecutionCount++; }//if // Calculate key length and renumber attribute id:s AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool; LocalDataBuffer<11> afterValues(pool, firedTriggerData->afterValues); bool skipNull = false; for(bool moreKeyAttrs = afterValues.first(iter); moreKeyAttrs; attrId++) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; // Filter out NULL valued attributes if (attrHeader->isNULL()) { skipNull = true; break; } attrHeader->setAttributeId(attrId); keyLength += attrHeader->getDataSize(); hops = attrHeader->getHeaderSize() + attrHeader->getDataSize(); moreKeyAttrs = afterValues.next(iter, hops); } if (skipNull) { jam(); opRecord->triggerExecutionCount--; if (opRecord->triggerExecutionCount == 0) { /* We have completed current trigger execution Continue triggering operation */ jam(); continueTriggeringOp(signal, opRecord); }//if return; }//if // Calculate total length of primary key to be stored in index table LocalDataBuffer<11> keyValues(pool, firedTriggerData->keyValues); for(bool moreAttrData = keyValues.first(iter); moreAttrData; ) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; totalPrimaryKeyLength += attrHeader->getDataSize(); hops = attrHeader->getHeaderSize() + attrHeader->getDataSize(); moreAttrData = keyValues.next(iter, hops); } AttributeHeader pkAttrHeader(attrId, totalPrimaryKeyLength << 2); Uint32 attributesLength = afterValues.getSize() + pkAttrHeader.getHeaderSize() + pkAttrHeader.getDataSize(); TcKeyReq::setKeyLength(tcKeyRequestInfo, keyLength); tcKeyReq->attrLen = attributesLength; tcKeyReq->tableId = indexData->indexId; TcKeyReq::setOperationType(tcKeyRequestInfo, ZINSERT); TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, true); tcKeyReq->tableSchemaVersion = indexTabPtr.p->currentSchemaVersion; tcKeyReq->transId1 = regApiPtr->transid[0]; tcKeyReq->transId2 = regApiPtr->transid[1]; Uint32 * dataPtr = &tcKeyReq->scanInfo; // Write first part of key in TCKEYREQ Uint32 keyBufSize = 8; // Maximum for key in TCKEYREQ Uint32 attrBufSize = 5; // Maximum for key in TCKEYREQ Uint32 dataPos = 0; // Filter out AttributeHeader:s since this should no be in key bool moreKeyData = afterValues.first(iter); Uint32 headerSize = 0, keyAttrSize = 0, dataSize = 0, headAndData = 0; while (moreKeyData && (dataPos < keyBufSize)) { /* * If we have not read complete key * and it fits in the signal */ jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); keyAttrSize = attrHeader->getDataSize(); headAndData = headerSize + attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreKeyData = afterValues.next(iter); } else { jam(); moreKeyData = afterValues.next(iter, headerSize - 1); }//if while((keyAttrSize != 0) && (dataPos < keyBufSize)) { // If we have not read complete key jam(); *dataPtr++ = *iter.data; dataPos++; keyAttrSize--; moreKeyData = afterValues.next(iter); } if (keyAttrSize != 0) { jam(); break; }//if } tcKeyLength += dataPos; /* Size of attrinfo is unique index attributes one by one, header for each of them (all contained in the afterValues data structure), plus a header, the primary key (compacted) and the fragment id before the primary key */ if (attributesLength <= attrBufSize) { jam(); // ATTRINFO fits in TCKEYREQ // Pack ATTRINFO IN TCKEYREQ as one attribute TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, attributesLength); bool moreAttrData; // Insert primary key attributes (insert after values of primary table) for(moreAttrData = afterValues.first(iter); moreAttrData; moreAttrData = afterValues.next(iter)) { *dataPtr++ = *iter.data; } // Insert attribute values (insert key values of primary table) // as one attribute pkAttrHeader.insertHeader(dataPtr); dataPtr += pkAttrHeader.getHeaderSize(); /* Insert fragment id before primary key as part of reference to tuple */ *dataPtr++ = firedTriggerData->fragId; moreAttrData = keyValues.first(iter); while(moreAttrData) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); dataSize = attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreAttrData = keyValues.next(iter); } else { jam(); moreAttrData = keyValues.next(iter, headerSize - 1); }//if // Copy attribute data while(dataSize-- != 0) { *dataPtr++ = *iter.data; moreAttrData = keyValues.next(iter); } } tcKeyLength += attributesLength; } else { jam(); // No ATTRINFO in TCKEYREQ TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 0); } tcKeyReq->requestInfo = tcKeyRequestInfo; /** * Fix savepoint id - * fix so that insert has same savepoint id as triggering operation */ const Uint32 currSavePointId = regApiPtr->currSavePointId; regApiPtr->currSavePointId = opRecord->savePointId; EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } regApiPtr->currSavePointId = currSavePointId; tcConnectptr.p->currentIndexId = indexData->indexId; // *********** KEYINFO *********** if (moreKeyData) { jam(); // Send KEYINFO sequence KeyInfo * const keyInfo = (KeyInfo *)signal->getDataPtrSend(); keyInfo->connectPtr = transPtr->i; keyInfo->transId[0] = regApiPtr->transid[0]; keyInfo->transId[1] = regApiPtr->transid[1]; dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; // Pack any part of a key attribute that did no fit TCKEYREQ while((keyAttrSize != 0) && (dataPos < KeyInfo::DataLength)) { // If we have not read complete key *dataPtr++ = *iter.data; dataPos++; keyAttrSize--; if (dataPos == KeyInfo::DataLength) { jam(); // Flush KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; } moreKeyData = afterValues.next(iter); } while(moreKeyData) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); keyAttrSize = attrHeader->getDataSize(); headAndData = headerSize + attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreKeyData = afterValues.next(iter); } else { jam(); moreKeyData = afterValues.next(iter, headerSize - 1); }//if while (keyAttrSize-- != 0) { *dataPtr++ = *iter.data; dataPos++; if (dataPos == KeyInfo::DataLength) { jam(); // Flush KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; } moreKeyData = afterValues.next(iter); } } if (dataPos != 0) { jam(); // Flush last KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } } } // *********** ATTRINFO *********** if (attributesLength > attrBufSize) { jam(); // No ATTRINFO in TcKeyReq TcKeyReq::setAIInTcKeyReq(tcKeyReq->requestInfo, 0); // Send ATTRINFO sequence AttrInfo * const attrInfo = (AttrInfo *)signal->getDataPtrSend(); Uint32 attrInfoPos = 0; attrInfo->connectPtr = transPtr->i; attrInfo->transId[0] = regApiPtr->transid[0]; attrInfo->transId[1] = regApiPtr->transid[1]; dataPtr = (Uint32 *) &attrInfo->attrData; bool moreAttrData; // Insert primary key attributes (insert after values of primary table) for(moreAttrData = afterValues.first(iter); moreAttrData; moreAttrData = afterValues.next(iter)) { *dataPtr++ = *iter.data; attrInfoPos++; if (attrInfoPos == AttrInfo::DataLength) { jam(); // Flush ATTRINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &attrInfo->attrData; attrInfoPos = 0; } } // Insert attribute values (insert key values of primary table) // as one attribute pkAttrHeader.insertHeader(dataPtr); dataPtr += pkAttrHeader.getHeaderSize(); attrInfoPos += pkAttrHeader.getHeaderSize(); /* Add fragment id before primary key TODO: This code really needs to be made into a long signal to remove this messy code. */ if (attrInfoPos == AttrInfo::DataLength) { jam(); // Flush ATTRINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength); jamEntry(); #endif dataPtr = (Uint32 *) &attrInfo->attrData; attrInfoPos = 0; } attrInfoPos++; *dataPtr++ = firedTriggerData->fragId; moreAttrData = keyValues.first(iter); while(moreAttrData) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); dataSize = attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreAttrData = keyValues.next(iter); } else { jam(); moreAttrData = keyValues.next(iter, headerSize - 1); }//if while(dataSize-- != 0) { // If we have not read complete key if (attrInfoPos == AttrInfo::DataLength) { jam(); // Flush ATTRINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + AttrInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &attrInfo->attrData; attrInfoPos = 0; } *dataPtr++ = *iter.data; attrInfoPos++; moreAttrData = keyValues.next(iter); } } if (attrInfoPos != 0) { jam(); // Flush last ATTRINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_ATTRINFO, signal, AttrInfo::HeaderLength + attrInfoPos, JBA); #else EXECUTE_DIRECT(DBTC, GSN_ATTRINFO, signal, AttrInfo::HeaderLength + attrInfoPos); jamEntry(); #endif } } } void Dbtc::deleteFromIndexTable(Signal* signal, TcFiredTriggerData* firedTriggerData, ApiConnectRecordPtr* transPtr, TcConnectRecordPtr* opPtr, TcIndexData* indexData, bool holdOperation) { ApiConnectRecord* regApiPtr = transPtr->p; TcConnectRecord* opRecord = opPtr->p; TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend(); Uint32 tcKeyRequestInfo = 0; Uint32 tcKeyLength = 12; // Static length TableRecordPtr indexTabPtr; AttributeBuffer::DataBufferIterator iter; Uint32 attrId = 0; Uint32 keyLength = 0; Uint32 hops; indexTabPtr.i = indexData->indexId; ptrCheckGuard(indexTabPtr, ctabrecFilesize, tableRecord); tcKeyReq->apiConnectPtr = transPtr->i; tcKeyReq->senderData = opPtr->i; if (holdOperation) { jam(); opRecord->triggerExecutionCount++; }//if // Calculate key length and renumber attribute id:s AttributeBuffer::DataBufferPool & pool = c_theAttributeBufferPool; LocalDataBuffer<11> beforeValues(pool, firedTriggerData->beforeValues); bool skipNull = false; for(bool moreKeyAttrs = beforeValues.first(iter); (moreKeyAttrs); attrId++) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; // Filter out NULL valued attributes if (attrHeader->isNULL()) { skipNull = true; break; } attrHeader->setAttributeId(attrId); keyLength += attrHeader->getDataSize(); hops = attrHeader->getHeaderSize() + attrHeader->getDataSize(); moreKeyAttrs = beforeValues.next(iter, hops); } if (skipNull) { jam(); opRecord->triggerExecutionCount--; if (opRecord->triggerExecutionCount == 0) { /* We have completed current trigger execution Continue triggering operation */ jam(); continueTriggeringOp(signal, opRecord); }//if return; }//if TcKeyReq::setKeyLength(tcKeyRequestInfo, keyLength); tcKeyReq->attrLen = 0; tcKeyReq->tableId = indexData->indexId; TcKeyReq::setOperationType(tcKeyRequestInfo, ZDELETE); TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, true); tcKeyReq->tableSchemaVersion = indexTabPtr.p->currentSchemaVersion; tcKeyReq->transId1 = regApiPtr->transid[0]; tcKeyReq->transId2 = regApiPtr->transid[1]; Uint32 * dataPtr = &tcKeyReq->scanInfo; // Write first part of key in TCKEYREQ Uint32 keyBufSize = 8; // Maximum for key in TCKEYREQ Uint32 dataPos = 0; // Filter out AttributeHeader:s since this should no be in key bool moreKeyData = beforeValues.first(iter); Uint32 headerSize = 0, keyAttrSize = 0, headAndData = 0; while (moreKeyData && (dataPos < keyBufSize)) { /* If we have not read complete key and it fits in the signal */ jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); keyAttrSize = attrHeader->getDataSize(); headAndData = headerSize + attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreKeyData = beforeValues.next(iter); } else { jam(); moreKeyData = beforeValues.next(iter, headerSize - 1); }//if while((keyAttrSize != 0) && (dataPos < keyBufSize)) { // If we have not read complete key jam(); *dataPtr++ = *iter.data; dataPos++; keyAttrSize--; moreKeyData = beforeValues.next(iter); } if (keyAttrSize != 0) { jam(); break; }//if } tcKeyLength += dataPos; tcKeyReq->requestInfo = tcKeyRequestInfo; /** * Fix savepoint id - * fix so that delete has same savepoint id as triggering operation */ const Uint32 currSavePointId = regApiPtr->currSavePointId; regApiPtr->currSavePointId = opRecord->savePointId; EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); jamEntry(); if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } regApiPtr->currSavePointId = currSavePointId; tcConnectptr.p->currentIndexId = indexData->indexId; // *********** KEYINFO *********** if (moreKeyData) { jam(); // Send KEYINFO sequence KeyInfo * const keyInfo = (KeyInfo *)signal->getDataPtrSend(); keyInfo->connectPtr = transPtr->i; keyInfo->transId[0] = regApiPtr->transid[0]; keyInfo->transId[1] = regApiPtr->transid[1]; dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; // Pack any part of a key attribute that did no fit TCKEYREQ while((keyAttrSize != 0) && (dataPos < KeyInfo::DataLength)) { // If we have not read complete key *dataPtr++ = *iter.data; dataPos++; keyAttrSize--; if (dataPos == KeyInfo::DataLength) { jam(); // Flush KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; } moreKeyData = beforeValues.next(iter); } while(moreKeyData) { jam(); AttributeHeader* attrHeader = (AttributeHeader *) iter.data; headerSize = attrHeader->getHeaderSize(); keyAttrSize = attrHeader->getDataSize(); headAndData = headerSize + attrHeader->getDataSize(); // Skip header if (headerSize == 1) { jam(); moreKeyData = beforeValues.next(iter); } else { jam(); moreKeyData = beforeValues.next(iter, headerSize - 1); }//if while (keyAttrSize-- != 0) { *dataPtr++ = *iter.data; dataPos++; if (dataPos == KeyInfo::DataLength) { jam(); // Flush KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + KeyInfo::DataLength); jamEntry(); #endif if (unlikely(regApiPtr->apiConnectstate == CS_ABORTING)) { jam(); return; } dataPtr = (Uint32 *) &keyInfo->keyData; dataPos = 0; } moreKeyData = beforeValues.next(iter); } } if (dataPos != 0) { jam(); // Flush last KEYINFO #if INTERNAL_TRIGGER_TCKEYREQ_JBA sendSignal(reference(), GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos, JBA); #else EXECUTE_DIRECT(DBTC, GSN_KEYINFO, signal, KeyInfo::HeaderLength + dataPos); jamEntry(); #endif } } } Uint32 Dbtc::TableRecord::getErrorCode(Uint32 schemaVersion) const { if(!get_enabled()) return ZNO_SUCH_TABLE; if(get_dropping()) return ZDROP_TABLE_IN_PROGRESS; if(table_version_major(schemaVersion) != table_version_major(currentSchemaVersion)) return ZWRONG_SCHEMA_VERSION_ERROR; ErrorReporter::handleAssert("Dbtc::TableRecord::getErrorCode", __FILE__, __LINE__); return 0; } void Dbtc::execROUTE_ORD(Signal* signal) { jamEntry(); if(!assembleFragments(signal)){ jam(); return; } RouteOrd* ord = (RouteOrd*)signal->getDataPtr(); Uint32 dstRef = ord->dstRef; Uint32 srcRef = ord->srcRef; Uint32 gsn = ord->gsn; if (likely(getNodeInfo(refToNode(dstRef)).m_connected)) { jam(); Uint32 secCount = signal->getNoOfSections(); SegmentedSectionPtr ptr[3]; ndbrequire(secCount >= 1 && secCount <= 3); jamLine(secCount); for (Uint32 i = 0; igetSection(ptr[i], i); /** * Put section 0 in signal->theData */ ndbrequire(ptr[0].sz <= 25); copy(signal->theData, ptr[0]); signal->header.m_noOfSections = 0; /** * Shift rest of sections */ for(Uint32 i = 1; isetSection(ptr[i], i - 1); } sendSignal(dstRef, gsn, signal, ptr[0].sz, JBB); signal->header.m_noOfSections = 0; signal->setSection(ptr[0], 0); releaseSections(signal); return ; } warningEvent("Unable to route GSN: %d from %x to %x", gsn, srcRef, dstRef); }