/* Copyright (C) 2003 MySQL AB 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; either version 2 of the License, or (at your option) any later version. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define DBLQH_C #include "Dblqh.hpp" #include <ndb_limits.h> #include <md5_hash.hpp> #include <ndb_version.h> #include <signaldata/TuxBound.hpp> #include <signaldata/AccScan.hpp> #include <signaldata/CopyActive.hpp> #include <signaldata/CopyFrag.hpp> #include <signaldata/CreateTrig.hpp> #include <signaldata/DropTrig.hpp> #include <signaldata/EmptyLcp.hpp> #include <signaldata/EventReport.hpp> #include <signaldata/ExecFragReq.hpp> #include <signaldata/GCPSave.hpp> #include <signaldata/TcKeyRef.hpp> #include <signaldata/LqhKey.hpp> #include <signaldata/NextScan.hpp> #include <signaldata/NFCompleteRep.hpp> #include <signaldata/NodeFailRep.hpp> #include <signaldata/ReadNodesConf.hpp> #include <signaldata/RelTabMem.hpp> #include <signaldata/ScanFrag.hpp> #include <signaldata/SrFragidConf.hpp> #include <signaldata/StartFragReq.hpp> #include <signaldata/StartRec.hpp> #include <signaldata/TupKey.hpp> #include <signaldata/TupCommit.hpp> #include <signaldata/LqhFrag.hpp> #include <signaldata/AccFrag.hpp> #include <signaldata/TupFrag.hpp> #include <signaldata/DumpStateOrd.hpp> #include <signaldata/PackedSignal.hpp> #include <signaldata/PrepDropTab.hpp> #include <signaldata/DropTab.hpp> #include <signaldata/AlterTab.hpp> #include <signaldata/LCP.hpp> // Use DEBUG to print messages that should be // seen only when we debug the product #ifdef VM_TRACE #define DEBUG(x) ndbout << "DBLQH: "<< x << endl; NdbOut & operator<<(NdbOut& out, Dblqh::TcConnectionrec::TransactionState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::TcConnectionrec::LogWriteState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::TcConnectionrec::ListState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::TcConnectionrec::AbortState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::ScanRecord::ScanState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::LogFileOperationRecord::LfoState state){ out << (int)state; return out; } NdbOut & operator<<(NdbOut& out, Dblqh::ScanRecord::ScanType state){ out << (int)state; return out; } #else #define DEBUG(x) #endif //#define MARKER_TRACE 1 //#define TRACE_SCAN_TAKEOVER 1 const Uint32 NR_ScanNo = 0; void Dblqh::execACC_COM_BLOCK(Signal* signal) { jamEntry(); /* ------------------------------------------------------------------------- */ // Undo log buffer in ACC is in critical sector of being full. /* ------------------------------------------------------------------------- */ cCounterAccCommitBlocked++; caccCommitBlocked = true; cCommitBlocked = true; return; }//Dblqh::execACC_COM_BLOCK() void Dblqh::execACC_COM_UNBLOCK(Signal* signal) { jamEntry(); /* ------------------------------------------------------------------------- */ // Undo log buffer in ACC ok again. /* ------------------------------------------------------------------------- */ caccCommitBlocked = false; if (ctupCommitBlocked == false) { jam(); cCommitBlocked = false; }//if return; }//Dblqh::execACC_COM_UNBLOCK() void Dblqh::execTUP_COM_BLOCK(Signal* signal) { jamEntry(); /* ------------------------------------------------------------------------- */ // Undo log buffer in TUP is in critical sector of being full. /* ------------------------------------------------------------------------- */ cCounterTupCommitBlocked++; ctupCommitBlocked = true; cCommitBlocked = true; return; }//Dblqh::execTUP_COM_BLOCK() void Dblqh::execTUP_COM_UNBLOCK(Signal* signal) { jamEntry(); /* ------------------------------------------------------------------------- */ // Undo log buffer in TUP ok again. /* ------------------------------------------------------------------------- */ ctupCommitBlocked = false; if (caccCommitBlocked == false) { jam(); cCommitBlocked = false; }//if return; }//Dblqh::execTUP_COM_UNBLOCK() /* ------------------------------------------------------------------------- */ /* ------- SEND SYSTEM ERROR ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::systemError(Signal* signal) { progError(0, 0); }//Dblqh::systemError() /* *************** */ /* ACCSEIZEREF > */ /* *************** */ void Dblqh::execACCSEIZEREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execACCSEIZEREF() /* ******************************************************>> */ /* THIS SIGNAL IS USED TO HANDLE REAL-TIME */ /* BREAKS THAT ARE NECESSARY TO ENSURE REAL-TIME */ /* OPERATION OF LQH. */ /* This signal is also used for signal loops, for example */ /* the timeout handling for writing logs every second. */ /* ******************************************************>> */ void Dblqh::execCONTINUEB(Signal* signal) { jamEntry(); Uint32 tcase = signal->theData[0]; Uint32 data0 = signal->theData[1]; Uint32 data1 = signal->theData[2]; Uint32 data2 = signal->theData[3]; #if 0 if (tcase == RNIL) { tcConnectptr.i = data0; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); ndbout << "State = " << tcConnectptr.p->transactionState; ndbout << " seqNoReplica = " << tcConnectptr.p->seqNoReplica; ndbout << " tcNodeFailrec = " << tcConnectptr.p->tcNodeFailrec; ndbout << " activeCreat = " << tcConnectptr.p->activeCreat; ndbout << endl; ndbout << "tupkeyData0 = " << tcConnectptr.p->tupkeyData[0]; ndbout << "tupkeyData1 = " << tcConnectptr.p->tupkeyData[1]; ndbout << "tupkeyData2 = " << tcConnectptr.p->tupkeyData[2]; ndbout << "tupkeyData3 = " << tcConnectptr.p->tupkeyData[3]; ndbout << endl; ndbout << "abortState = " << tcConnectptr.p->abortState; ndbout << "listState = " << tcConnectptr.p->listState; ndbout << endl; return; }//if #endif switch (tcase) { case ZLOG_LQHKEYREQ: if (cnoOfLogPages == 0) { jam(); sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); return; }//if logPartPtr.i = data0; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); tcConnectptr.i = logPartPtr.p->firstLogQueue; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if ((cCommitBlocked == true) && (fragptr.p->fragActiveStatus == ZTRUE)) { jam(); sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); return; }//if logPartPtr.p->LogLqhKeyReqSent = ZFALSE; getFirstInLogQueue(signal); switch (tcConnectptr.p->transactionState) { case TcConnectionrec::LOG_QUEUED: if (tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE) { jam(); logNextStart(signal); abortCommonLab(signal); return; } else { jam(); /*------------------------------------------------------------*/ /* WE MUST SET THE STATE OF THE LOG PART TO IDLE TO */ /* ENSURE THAT WE ARE NOT QUEUED AGAIN ON THE LOG PART */ /* WE WILL SET THE LOG PART STATE TO ACTIVE IMMEDIATELY */ /* SO NO OTHER PROCESS WILL SEE THIS STATE. IT IS MERELY*/ /* USED TO ENABLE REUSE OF CODE. */ /*------------------------------------------------------------*/ if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { jam(); logPartPtr.p->logPartState = LogPartRecord::IDLE; }//if logLqhkeyreqLab(signal); return; }//if break; case TcConnectionrec::LOG_ABORT_QUEUED: jam(); writeAbortLog(signal); removeLogTcrec(signal); logNextStart(signal); continueAfterLogAbortWriteLab(signal); return; break; case TcConnectionrec::LOG_COMMIT_QUEUED: case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: jam(); writeCommitLog(signal, logPartPtr); logNextStart(signal); if (tcConnectptr.p->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) { if (tcConnectptr.p->seqNoReplica != 0) { jam(); commitReplyLab(signal); } else { jam(); localCommitLab(signal); }//if return; } else { jam(); tcConnectptr.p->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL; return; }//if break; case TcConnectionrec::COMMIT_QUEUED: jam(); logNextStart(signal); localCommitLab(signal); break; case TcConnectionrec::ABORT_QUEUED: jam(); logNextStart(signal); abortCommonLab(signal); break; default: ndbrequire(false); break; }//switch return; break; case ZSR_GCI_LIMITS: jam(); signal->theData[0] = data0; srGciLimits(signal); return; break; case ZSR_LOG_LIMITS: jam(); signal->theData[0] = data0; signal->theData[1] = data1; signal->theData[2] = data2; srLogLimits(signal); return; break; case ZSEND_EXEC_CONF: jam(); signal->theData[0] = data0; sendExecConf(signal); return; break; case ZEXEC_SR: jam(); signal->theData[0] = data0; execSr(signal); return; break; case ZSR_FOURTH_COMP: jam(); signal->theData[0] = data0; srFourthComp(signal); return; break; case ZINIT_FOURTH: jam(); signal->theData[0] = data0; initFourth(signal); return; break; case ZTIME_SUPERVISION: jam(); signal->theData[0] = data0; timeSup(signal); return; break; case ZSR_PHASE3_START: jam(); signal->theData[0] = data0; srPhase3Start(signal); return; break; case ZLQH_TRANS_NEXT: jam(); tcNodeFailptr.i = data0; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); lqhTransNextLab(signal); return; break; case ZSCAN_TC_CONNECT: jam(); tabptr.i = data1; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); scanTcConnectLab(signal, data0, data2); return; break; case ZINITIALISE_RECORDS: jam(); initialiseRecordsLab(signal, data0, data2, signal->theData[4]); return; break; case ZINIT_GCP_REC: jam(); gcpPtr.i = 0; ptrAss(gcpPtr, gcpRecord); initGcpRecLab(signal); return; break; case ZRESTART_OPERATIONS_AFTER_STOP: jam(); tcConnectptr.i = data0; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); if (tcConnectptr.p->listState != TcConnectionrec::WAIT_QUEUE_LIST) { jam(); return; }//if releaseWaitQueue(signal); linkActiveFrag(signal); restartOperationsAfterStopLab(signal); return; break; case ZCHECK_LCP_STOP_BLOCKED: jam(); c_scanRecordPool.getPtr(scanptr, data0); tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); checkLcpStopBlockedLab(signal); return; case ZSCAN_MARKERS: jam(); scanMarkers(signal, data0, data1, data2); return; break; case ZOPERATION_EVENT_REP: jam(); /* --------------------------------------------------------------------- */ // Report information about transaction activity once per second. /* --------------------------------------------------------------------- */ if (signal->theData[1] == 0) { signal->theData[0] = EventReport::OperationReportCounters; signal->theData[1] = c_Counters.operations; sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB); }//if c_Counters.clear(); signal->theData[0] = ZOPERATION_EVENT_REP; signal->theData[1] = 0; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 5000, 2); break; case ZPREP_DROP_TABLE: jam(); checkDropTab(signal); return; break; default: ndbrequire(false); break; }//switch }//Dblqh::execCONTINUEB() /* *********************************************************> */ /* Request from DBDIH to include a new node in the node list */ /* and so forth. */ /* *********************************************************> */ void Dblqh::execINCL_NODEREQ(Signal* signal) { jamEntry(); BlockReference retRef = signal->theData[0]; Uint32 nodeId = signal->theData[1]; cnewestGci = signal->theData[2]; cnewestCompletedGci = signal->theData[2] - 1; ndbrequire(cnoOfNodes < MAX_NDB_NODES); for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); if (cnodeData[i] == nodeId) { jam(); cnodeStatus[i] = ZNODE_UP; }//if }//for signal->theData[0] = cownref; sendSignal(retRef, GSN_INCL_NODECONF, signal, 1, JBB); return; }//Dblqh::execINCL_NODEREQ() void Dblqh::execTUPSEIZEREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execTUPSEIZEREF() /* ########################################################################## */ /* ####### START / RESTART MODULE ####### */ /* ########################################################################## */ /* ************************************************************************>> */ /* This is first signal that arrives in a start / restart. Sender is NDBCNTR_REF. */ /* ************************************************************************>> */ void Dblqh::execSTTOR(Signal* signal) { UintR tstartPhase; jamEntry(); /* START CASE */ tstartPhase = signal->theData[1]; /* SYSTEM RESTART RANK */ csignalKey = signal->theData[6]; switch (tstartPhase) { case ZSTART_PHASE1: jam(); cstartPhase = tstartPhase; sttorStartphase1Lab(signal); return; break; default: jam(); /*empty*/; sendsttorryLab(signal); return; break; }//switch }//Dblqh::execSTTOR() /* ***************************************> */ /* Restart phases 1 - 6, sender is Ndbcntr */ /* ***************************************> */ void Dblqh::execNDB_STTOR(Signal* signal) { jamEntry(); Uint32 ownNodeId = signal->theData[1]; /* START PHASE*/ cstartPhase = signal->theData[2]; /* MY NODE ID */ cstartType = signal->theData[3]; /* START TYPE */ switch (cstartPhase) { case ZSTART_PHASE1: jam(); preComputedRequestInfoMask = 0; LqhKeyReq::setKeyLen(preComputedRequestInfoMask, RI_KEYLEN_MASK); LqhKeyReq::setLastReplicaNo(preComputedRequestInfoMask, RI_LAST_REPL_MASK); LqhKeyReq::setLockType(preComputedRequestInfoMask, RI_LOCK_TYPE_MASK); // Dont LqhKeyReq::setApplicationAddressFlag LqhKeyReq::setDirtyFlag(preComputedRequestInfoMask, 1); // Dont LqhKeyReq::setInterpretedFlag LqhKeyReq::setSimpleFlag(preComputedRequestInfoMask, 1); LqhKeyReq::setOperation(preComputedRequestInfoMask, RI_OPERATION_MASK); // Dont setAIInLqhKeyReq // Dont setSeqNoReplica // Dont setSameClientAndTcFlag // Dont setReturnedReadLenAIFlag // Dont setAPIVersion LqhKeyReq::setMarkerFlag(preComputedRequestInfoMask, 1); //preComputedRequestInfoMask = 0x003d7fff; startphase1Lab(signal, /* dummy */ ~0, ownNodeId); signal->theData[0] = ZOPERATION_EVENT_REP; signal->theData[1] = 1; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); return; break; case ZSTART_PHASE2: jam(); startphase2Lab(signal, /* dummy */ ~0); return; break; case ZSTART_PHASE3: jam(); startphase3Lab(signal); return; break; case ZSTART_PHASE4: jam(); startphase4Lab(signal); return; break; case ZSTART_PHASE6: jam(); startphase6Lab(signal); return; break; default: jam(); /*empty*/; sendNdbSttorryLab(signal); return; break; }//switch }//Dblqh::execNDB_STTOR() /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* +++++++ START PHASE 1 +++++++ */ /* LOAD OUR BLOCK REFERENCE AND OUR PROCESSOR ID */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void Dblqh::sttorStartphase1Lab(Signal* signal) { sendsttorryLab(signal); return; }//Dblqh::sttorStartphase1Lab() /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* +++++++ START PHASE 2 +++++++ */ /* */ /* INITIATE ALL RECORDS WITHIN THE BLOCK */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void Dblqh::startphase1Lab(Signal* signal, Uint32 _dummy, Uint32 ownNodeId) { UintR Ti; HostRecordPtr ThostPtr; /* ------- INITIATE ALL RECORDS ------- */ cownNodeid = ownNodeId; caccBlockref = calcAccBlockRef (cownNodeid); ctupBlockref = calcTupBlockRef (cownNodeid); ctuxBlockref = calcTuxBlockRef (cownNodeid); cownref = calcLqhBlockRef (cownNodeid); for (Ti = 0; Ti < chostFileSize; Ti++) { ThostPtr.i = Ti; ptrCheckGuard(ThostPtr, chostFileSize, hostRecord); ThostPtr.p->hostLqhBlockRef = calcLqhBlockRef(ThostPtr.i); ThostPtr.p->hostTcBlockRef = calcTcBlockRef(ThostPtr.i); ThostPtr.p->inPackedList = false; ThostPtr.p->noOfPackedWordsLqh = 0; ThostPtr.p->noOfPackedWordsTc = 0; }//for cpackedListIndex = 0; sendNdbSttorryLab(signal); return; }//Dblqh::startphase1Lab() /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* +++++++ START PHASE 2 +++++++ */ /* */ /* CONNECT LQH WITH ACC AND TUP. */ /* EVERY CONNECTION RECORD IN LQH IS ASSIGNED TO ONE ACC CONNECTION RECORD */ /* AND ONE TUP CONNECTION RECORD. */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void Dblqh::startphase2Lab(Signal* signal, Uint32 _dummy) { cmaxWordsAtNodeRec = MAX_NO_WORDS_OUTSTANDING_COPY_FRAGMENT; /* -- ACC AND TUP CONNECTION PROCESS -- */ tcConnectptr.i = 0; ptrAss(tcConnectptr, tcConnectionrec); moreconnectionsLab(signal); return; }//Dblqh::startphase2Lab() void Dblqh::moreconnectionsLab(Signal* signal) { tcConnectptr.p->tcAccBlockref = caccBlockref; // set TUX block here (no operation is seized in TUX) tcConnectptr.p->tcTuxBlockref = ctuxBlockref; /* NO STATE CHECKING IS PERFORMED, ASSUMED TO WORK */ /* *************** */ /* ACCSEIZEREQ < */ /* *************** */ signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; sendSignal(caccBlockref, GSN_ACCSEIZEREQ, signal, 2, JBB); return; }//Dblqh::moreconnectionsLab() /* ***************> */ /* ACCSEIZECONF > */ /* ***************> */ void Dblqh::execACCSEIZECONF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); tcConnectptr.p->accConnectrec = signal->theData[1]; /* *************** */ /* TUPSEIZEREQ < */ /* *************** */ tcConnectptr.p->tcTupBlockref = ctupBlockref; signal->theData[0] = tcConnectptr.i; signal->theData[1] = cownref; sendSignal(ctupBlockref, GSN_TUPSEIZEREQ, signal, 2, JBB); return; }//Dblqh::execACCSEIZECONF() /* ***************> */ /* TUPSEIZECONF > */ /* ***************> */ void Dblqh::execTUPSEIZECONF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); tcConnectptr.p->tupConnectrec = signal->theData[1]; /* ------- CHECK IF THERE ARE MORE CONNECTIONS TO BE CONNECTED ------- */ tcConnectptr.i = tcConnectptr.p->nextTcConnectrec; if (tcConnectptr.i != RNIL) { jam(); ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); moreconnectionsLab(signal); return; }//if /* ALL LQH_CONNECT RECORDS ARE CONNECTED TO ACC AND TUP ---- */ sendNdbSttorryLab(signal); return; }//Dblqh::execTUPSEIZECONF() /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* +++++++ START PHASE 4 +++++++ */ /* */ /* CONNECT LQH WITH LQH. */ /* CONNECT EACH LQH WITH EVERY LQH IN THE DATABASE SYSTEM. */ /* IF INITIAL START THEN CREATE THE FRAGMENT LOG FILES */ /*IF SYSTEM RESTART OR NODE RESTART THEN OPEN THE FRAGMENT LOG FILES AND */ /*FIND THE END OF THE LOG FILES. */ /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* WAIT UNTIL ADD NODE PROCESSES ARE COMPLETED */ /* IF INITIAL START ALSO WAIT FOR LOG FILES TO INITIALISED */ /*START TIME SUPERVISION OF LOG FILES. WE HAVE TO WRITE LOG PAGES TO DISK */ /*EVEN IF THE PAGES ARE NOT FULL TO ENSURE THAT THEY COME TO DISK ASAP. */ /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void Dblqh::startphase3Lab(Signal* signal) { LogFileRecordPtr prevLogFilePtr; LogFileRecordPtr zeroLogFilePtr; caddNodeState = ZTRUE; /* ***************<< */ /* READ_NODESREQ < */ /* ***************<< */ cinitialStartOngoing = ZTRUE; ndbrequire(cnoLogFiles != 0); for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); initLogpart(signal); for (Uint32 fileNo = 0; fileNo < cnoLogFiles; fileNo++) { seizeLogfile(signal); if (fileNo != 0) { jam(); prevLogFilePtr.p->nextLogFile = logFilePtr.i; logFilePtr.p->prevLogFile = prevLogFilePtr.i; } else { jam(); logPartPtr.p->firstLogfile = logFilePtr.i; logPartPtr.p->currentLogfile = logFilePtr.i; zeroLogFilePtr.i = logFilePtr.i; zeroLogFilePtr.p = logFilePtr.p; }//if prevLogFilePtr.i = logFilePtr.i; prevLogFilePtr.p = logFilePtr.p; initLogfile(signal, fileNo); if ((cstartType == NodeState::ST_INITIAL_START) || (cstartType == NodeState::ST_INITIAL_NODE_RESTART)) { if (logFilePtr.i == zeroLogFilePtr.i) { jam(); /* ------------------------------------------------------------------------- */ /*IN AN INITIAL START WE START BY CREATING ALL LOG FILES AND SETTING THEIR */ /*PROPER SIZE AND INITIALISING PAGE ZERO IN ALL FILES. */ /*WE START BY CREATING FILE ZERO IN EACH LOG PART AND THEN PROCEED */ /*SEQUENTIALLY THROUGH ALL LOG FILES IN THE LOG PART. */ /* ------------------------------------------------------------------------- */ openLogfileInit(signal); }//if }//if }//for zeroLogFilePtr.p->prevLogFile = logFilePtr.i; logFilePtr.p->nextLogFile = zeroLogFilePtr.i; }//for if (cstartType != NodeState::ST_INITIAL_START && cstartType != NodeState::ST_INITIAL_NODE_RESTART) { jam(); ndbrequire(cstartType == NodeState::ST_NODE_RESTART || cstartType == NodeState::ST_SYSTEM_RESTART); /** -------------------------------------------------------------------- * THIS CODE KICKS OFF THE SYSTEM RESTART AND NODE RESTART. IT STARTS UP * THE RESTART BY FINDING THE END OF THE LOG AND FROM THERE FINDING THE * INFO ABOUT THE GLOBAL CHECKPOINTS IN THE FRAGMENT LOG. --------------------------------------------------------------------- */ for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { jam(); LogFileRecordPtr locLogFilePtr; ptrAss(logPartPtr, logPartRecord); locLogFilePtr.i = logPartPtr.p->firstLogfile; ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FRONTPAGE; openFileRw(signal, locLogFilePtr); }//for }//if signal->theData[0] = cownref; sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB); return; }//Dblqh::startphase3Lab() /* ****************** */ /* READ_NODESCONF > */ /* ****************** */ void Dblqh::execREAD_NODESCONF(Signal* signal) { jamEntry(); ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0]; cnoOfNodes = readNodes->noOfNodes; unsigned ind = 0; unsigned i = 0; for (i = 1; i < MAX_NDB_NODES; i++) { jam(); if (NodeBitmask::get(readNodes->allNodes, i)) { jam(); cnodeData[ind] = i; cnodeStatus[ind] = NodeBitmask::get(readNodes->inactiveNodes, i); //readNodes->getVersionId(i, readNodes->theVersionIds) not used ind++; }//if }//for ndbrequire(ind == cnoOfNodes); ndbrequire(cnoOfNodes >= 1 && cnoOfNodes < MAX_NDB_NODES); ndbrequire(!(cnoOfNodes == 1 && cstartType == NodeState::ST_NODE_RESTART)); caddNodeState = ZFALSE; if (cstartType == NodeState::ST_SYSTEM_RESTART) { jam(); sendNdbSttorryLab(signal); return; }//if checkStartCompletedLab(signal); return; }//Dblqh::execREAD_NODESCONF() void Dblqh::checkStartCompletedLab(Signal* signal) { if (caddNodeState == ZFALSE) { if (cinitialStartOngoing == ZFALSE) { jam(); sendNdbSttorryLab(signal); return; }//if }//if return; }//Dblqh::checkStartCompletedLab() void Dblqh::startphase4Lab(Signal* signal) { sendNdbSttorryLab(signal); return; }//Dblqh::startphase4Lab() /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* SET CONCURRENCY OF LOCAL CHECKPOINTS TO BE USED AFTER SYSTEM RESTART. */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void Dblqh::startphase6Lab(Signal* signal) { cstartPhase = ZNIL; cstartType = ZNIL; sendNdbSttorryLab(signal); return; }//Dblqh::startphase6Lab() void Dblqh::sendNdbSttorryLab(Signal* signal) { signal->theData[0] = cownref; sendSignal(NDBCNTR_REF, GSN_NDB_STTORRY, signal, 1, JBB); return; }//Dblqh::sendNdbSttorryLab() void Dblqh::sendsttorryLab(Signal* signal) { /* *********<< */ /* STTORRY < */ /* *********<< */ signal->theData[0] = csignalKey; /* SIGNAL KEY */ signal->theData[1] = 3; /* BLOCK CATEGORY */ signal->theData[2] = 2; /* SIGNAL VERSION NUMBER */ signal->theData[3] = ZSTART_PHASE1; signal->theData[4] = 255; sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 5, JBB); return; }//Dblqh::sendsttorryLab() /* ***************>> */ /* READ_NODESREF > */ /* ***************>> */ void Dblqh::execREAD_NODESREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execREAD_NODESREF() /* *************** */ /* SIZEALT_REP > */ /* *************** */ void Dblqh::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 = theConfiguration.getOwnConfigIterator(); ndbrequire(p != 0); cnoLogFiles = 8; ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_REDOLOG_FILES, &cnoLogFiles)); ndbrequire(cnoLogFiles > 0); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_FRAG, &cfragrecFileSize)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TABLE, &ctabrecFileSize)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TC_CONNECT, &ctcConnectrecFileSize)); clogFileFileSize = 4 * cnoLogFiles; ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_SCAN, &cscanrecFileSize)); cmaxAccOps = cscanrecFileSize * MAX_PARALLEL_OP_PER_SCAN; ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &c_diskless)); initRecords(); initialiseRecordsLab(signal, 0, ref, senderData); return; }//Dblqh::execSIZEALT_REP() /* ########################################################################## */ /* ####### ADD/DELETE FRAGMENT MODULE ####### */ /* THIS MODULE IS USED BY DICTIONARY TO CREATE NEW FRAGMENTS AND DELETE */ /* OLD FRAGMENTS. */ /* */ /* ########################################################################## */ /* -------------------------------------------------------------- */ /* FRAG REQ */ /* -------------------------------------------------------------- */ /* *********************************************************> */ /* LQHFRAGREQ: Create new fragments for a table. Sender DICT */ /* *********************************************************> */ void Dblqh::execLQHFRAGREQ(Signal* signal) { jamEntry(); LqhFragReq * req = (LqhFragReq*)signal->getDataPtr(); Uint32 retPtr = req->senderData; BlockReference retRef = req->senderRef; Uint32 fragId = req->fragmentId; Uint32 reqinfo = req->requestInfo; tabptr.i = req->tableId; Uint16 tlocalKeylen = req->localKeyLength; Uint32 tmaxLoadFactor = req->maxLoadFactor; Uint32 tminLoadFactor = req->minLoadFactor; Uint8 tk = req->kValue; Uint8 tlhstar = req->lh3DistrBits; Uint8 tlh = req->lh3PageBits; Uint32 tnoOfAttr = req->noOfAttributes; Uint32 tnoOfNull = req->noOfNullAttributes; Uint32 noOfAlloc = req->noOfPagesToPreAllocate; Uint32 tschemaVersion = req->schemaVersion; Uint32 ttupKeyLength = req->keyLength; Uint32 nextLcp = req->nextLCP; Uint32 noOfKeyAttr = req->noOfKeyAttr; Uint32 noOfNewAttr = req->noOfNewAttr; Uint32 checksumIndicator = req->checksumIndicator; Uint32 noOfAttributeGroups = req->noOfAttributeGroups; Uint32 gcpIndicator = req->GCPIndicator; Uint32 startGci = req->startGci; Uint32 tableType = req->tableType; Uint32 primaryTableId = req->primaryTableId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); bool tempTable = ((reqinfo & LqhFragReq::TemporaryTable) != 0); /* Temporary tables set to defined in system restart */ if (tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ tabptr.p->tableStatus = Tablerec::ADD_TABLE_ONGOING; tabptr.p->tableType = tableType; tabptr.p->primaryTableId = primaryTableId; tabptr.p->schemaVersion = tschemaVersion; }//if if (tabptr.p->tableStatus != Tablerec::ADD_TABLE_ONGOING){ jam(); fragrefLab(signal, retRef, retPtr, ZTAB_STATE_ERROR); return; }//if //-------------------------------------------------------------------- // We could arrive here if we create the fragment as part of a take // over by a hot spare node. The table is then is already created // and bit 31 is set, thus indicating that we are creating a fragment // by copy creation. Also since the node has already been started we // know that it is not a node restart ongoing. //-------------------------------------------------------------------- if (getFragmentrec(signal, fragId)) { jam(); fragrefLab(signal, retRef, retPtr, terrorCode); return; }//if if (!insertFragrec(signal, fragId)) { jam(); fragrefLab(signal, retRef, retPtr, terrorCode); return; }//if Uint32 copyType = reqinfo & 3; initFragrec(signal, tabptr.i, fragId, copyType); fragptr.p->startGci = startGci; fragptr.p->newestGci = startGci; fragptr.p->tableType = tableType; if (DictTabInfo::isOrderedIndex(tableType)) { jam(); // find corresponding primary table fragment TablerecPtr tTablePtr; tTablePtr.i = primaryTableId; ptrCheckGuard(tTablePtr, ctabrecFileSize, tablerec); FragrecordPtr tFragPtr; tFragPtr.i = RNIL; for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) { if (tTablePtr.p->fragid[i] == fragptr.p->fragId) { jam(); tFragPtr.i = tTablePtr.p->fragrec[i]; break; } } ndbrequire(tFragPtr.i != RNIL); // store it fragptr.p->tableFragptr = tFragPtr.i; } else { fragptr.p->tableFragptr = fragptr.i; } if (tempTable) { //-------------------------------------------- // reqinfo bit 3-4 = 2 means temporary table // without logging or checkpointing. //-------------------------------------------- jam(); fragptr.p->logFlag = Fragrecord::STATE_FALSE; fragptr.p->lcpFlag = Fragrecord::LCP_STATE_FALSE; }//if fragptr.p->nextLcp = nextLcp; //---------------------------------------------- // For node restarts it is not necessarily zero //---------------------------------------------- if (cfirstfreeAddfragrec == RNIL) { jam(); deleteFragrec(fragId); fragrefLab(signal, retRef, retPtr, ZNO_ADD_FRAGREC); return; }//if seizeAddfragrec(signal); addfragptr.p->addFragid = fragId; addfragptr.p->fragmentPtr = fragptr.i; addfragptr.p->dictBlockref = retRef; addfragptr.p->dictConnectptr = retPtr; addfragptr.p->m_senderAttrPtr = RNIL; addfragptr.p->noOfAttr = tnoOfAttr; addfragptr.p->noOfNull = tnoOfNull; addfragptr.p->noOfAllocPages = noOfAlloc; addfragptr.p->tabId = tabptr.i; addfragptr.p->totalAttrReceived = 0; addfragptr.p->attrSentToTup = ZNIL;/* TO FIND PROGRAMMING ERRORS QUICKLY */ addfragptr.p->schemaVer = tschemaVersion; Uint32 tmp = (reqinfo & LqhFragReq::CreateInRunning); addfragptr.p->fragCopyCreation = (tmp == 0 ? 0 : 1); addfragptr.p->addfragErrorCode = 0; addfragptr.p->noOfKeyAttr = noOfKeyAttr; addfragptr.p->noOfNewAttr = noOfNewAttr; addfragptr.p->checksumIndicator = checksumIndicator; addfragptr.p->noOfAttributeGroups = noOfAttributeGroups; addfragptr.p->GCPIndicator = gcpIndicator; addfragptr.p->lh3DistrBits = tlhstar; addfragptr.p->tableType = tableType; addfragptr.p->primaryTableId = primaryTableId; if (DictTabInfo::isTable(tableType) || DictTabInfo::isHashIndex(tableType)) { jam(); AccFragReq* const accreq = (AccFragReq*)signal->getDataPtrSend(); accreq->userPtr = addfragptr.i; accreq->userRef = cownref; accreq->tableId = tabptr.i; accreq->reqInfo = copyType << 4; accreq->fragId = fragId; accreq->localKeyLen = tlocalKeylen; accreq->maxLoadFactor = tmaxLoadFactor; accreq->minLoadFactor = tminLoadFactor; accreq->kValue = tk; accreq->lhFragBits = tlhstar; accreq->lhDirBits = tlh; accreq->keyLength = ttupKeyLength; /* ----------------------------------------------------------------------- */ /* Send ACCFRAGREQ, when confirmation is received send 2 * TUPFRAGREQ to */ /* create 2 tuple fragments on this node. */ /* ----------------------------------------------------------------------- */ addfragptr.p->addfragStatus = AddFragRecord::ACC_ADDFRAG; sendSignal(fragptr.p->accBlockref, GSN_ACCFRAGREQ, signal, AccFragReq::SignalLength, JBB); return; } if (DictTabInfo::isOrderedIndex(tableType)) { jam(); // NOTE: next 2 lines stolen from ACC addfragptr.p->fragid1 = (0 << tlhstar) | fragId; addfragptr.p->fragid2 = (1 << tlhstar) | fragId; addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUP; sendAddFragReq(signal); return; } ndbrequire(false); }//Dblqh::execLQHFRAGREQ() /* *************** */ /* ACCFRAGCONF > */ /* *************** */ void Dblqh::execACCFRAGCONF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; Uint32 taccConnectptr = signal->theData[1]; Uint32 fragId1 = signal->theData[2]; Uint32 fragId2 = signal->theData[3]; Uint32 accFragPtr1 = signal->theData[4]; Uint32 accFragPtr2 = signal->theData[5]; Uint32 hashCheckBit = signal->theData[6]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::ACC_ADDFRAG); addfragptr.p->accConnectptr = taccConnectptr; addfragptr.p->fragid1 = fragId1; addfragptr.p->fragid2 = fragId2; fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->accFragptr[0] = accFragPtr1; fragptr.p->accFragptr[1] = accFragPtr2; fragptr.p->hashCheckBit = hashCheckBit; addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUP; sendAddFragReq(signal); }//Dblqh::execACCFRAGCONF() /* *************** */ /* TUPFRAGCONF > */ /* *************** */ void Dblqh::execTUPFRAGCONF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; Uint32 tupConnectptr = signal->theData[1]; Uint32 tupFragPtr = signal->theData[2]; /* TUP FRAGMENT POINTER */ Uint32 localFragId = signal->theData[3]; /* LOCAL FRAGMENT ID */ ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (localFragId == addfragptr.p->fragid1) { jam(); fragptr.p->tupFragptr[0] = tupFragPtr; } else if (localFragId == addfragptr.p->fragid2) { jam(); fragptr.p->tupFragptr[1] = tupFragPtr; } else { ndbrequire(false); return; }//if switch (addfragptr.p->addfragStatus) { case AddFragRecord::WAIT_TWO_TUP: jam(); fragptr.p->tupFragptr[0] = tupFragPtr; addfragptr.p->tup1Connectptr = tupConnectptr; addfragptr.p->addfragStatus = AddFragRecord::WAIT_ONE_TUP; sendAddFragReq(signal); break; case AddFragRecord::WAIT_ONE_TUP: jam(); fragptr.p->tupFragptr[1] = tupFragPtr; addfragptr.p->tup2Connectptr = tupConnectptr; if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUX; sendAddFragReq(signal); break; } goto done_with_frag; break; case AddFragRecord::WAIT_TWO_TUX: jam(); fragptr.p->tuxFragptr[0] = tupFragPtr; addfragptr.p->tux1Connectptr = tupConnectptr; addfragptr.p->addfragStatus = AddFragRecord::WAIT_ONE_TUX; sendAddFragReq(signal); break; case AddFragRecord::WAIT_ONE_TUX: jam(); fragptr.p->tuxFragptr[1] = tupFragPtr; addfragptr.p->tux2Connectptr = tupConnectptr; goto done_with_frag; break; done_with_frag: /* ---------------------------------------------------------------- */ /* Finished create of fragments. Now ready for creating attributes. */ /* ---------------------------------------------------------------- */ addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR; { LqhFragConf* conf = (LqhFragConf*)signal->getDataPtrSend(); conf->senderData = addfragptr.p->dictConnectptr; conf->lqhFragPtr = addfragptr.i; sendSignal(addfragptr.p->dictBlockref, GSN_LQHFRAGCONF, signal, LqhFragConf::SignalLength, JBB); } break; default: ndbrequire(false); break; } }//Dblqh::execTUPFRAGCONF() /* *************** */ /* TUXFRAGCONF > */ /* *************** */ void Dblqh::execTUXFRAGCONF(Signal* signal) { jamEntry(); execTUPFRAGCONF(signal); }//Dblqh::execTUXFRAGCONF /* * Add fragment in TUP or TUX. Called up to 4 times. */ void Dblqh::sendAddFragReq(Signal* signal) { fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP || addfragptr.p->addfragStatus == AddFragRecord::WAIT_ONE_TUP) { if (DictTabInfo::isTable(addfragptr.p->tableType) || DictTabInfo::isHashIndex(addfragptr.p->tableType)) { jam(); signal->theData[0] = addfragptr.i; signal->theData[1] = cownref; signal->theData[2] = 0; /* ADD TABLE */ signal->theData[3] = addfragptr.p->tabId; signal->theData[4] = addfragptr.p->noOfAttr; signal->theData[5] = addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP ? addfragptr.p->fragid1 : addfragptr.p->fragid2; signal->theData[6] = (addfragptr.p->noOfAllocPages >> 1) + 1; signal->theData[7] = addfragptr.p->noOfNull; signal->theData[8] = addfragptr.p->schemaVer; signal->theData[9] = addfragptr.p->noOfKeyAttr; signal->theData[10] = addfragptr.p->noOfNewAttr; signal->theData[11] = addfragptr.p->checksumIndicator; signal->theData[12] = addfragptr.p->noOfAttributeGroups; signal->theData[13] = addfragptr.p->GCPIndicator; sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, TupFragReq::SignalLength, JBB); return; } if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { jam(); signal->theData[0] = addfragptr.i; signal->theData[1] = cownref; signal->theData[2] = 0; /* ADD TABLE */ signal->theData[3] = addfragptr.p->tabId; signal->theData[4] = 1; /* ordered index: one array attr */ signal->theData[5] = addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP ? addfragptr.p->fragid1 : addfragptr.p->fragid2; signal->theData[6] = (addfragptr.p->noOfAllocPages >> 1) + 1; signal->theData[7] = 0; /* ordered index: no nullable */ signal->theData[8] = addfragptr.p->schemaVer; signal->theData[9] = 1; /* ordered index: one key */ signal->theData[10] = addfragptr.p->noOfNewAttr; signal->theData[11] = addfragptr.p->checksumIndicator; signal->theData[12] = addfragptr.p->noOfAttributeGroups; signal->theData[13] = addfragptr.p->GCPIndicator; sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, TupFragReq::SignalLength, JBB); return; } } if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX || addfragptr.p->addfragStatus == AddFragRecord::WAIT_ONE_TUX) { if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { jam(); TuxFragReq* const tuxreq = (TuxFragReq*)signal->getDataPtrSend(); tuxreq->userPtr = addfragptr.i; tuxreq->userRef = cownref; tuxreq->reqInfo = 0; /* ADD TABLE */ tuxreq->tableId = addfragptr.p->tabId; ndbrequire(addfragptr.p->noOfAttr >= 2); tuxreq->noOfAttr = addfragptr.p->noOfAttr - 1; /* skip NDB$TNODE */ tuxreq->fragId = addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX ? addfragptr.p->fragid1 : addfragptr.p->fragid2; tuxreq->fragOff = addfragptr.p->lh3DistrBits; tuxreq->tableType = addfragptr.p->tableType; tuxreq->primaryTableId = addfragptr.p->primaryTableId; // pointer to index fragment in TUP tuxreq->tupIndexFragPtrI = addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX ? fragptr.p->tupFragptr[0] : fragptr.p->tupFragptr[1]; // pointers to table fragments in TUP and ACC FragrecordPtr tFragPtr; tFragPtr.i = fragptr.p->tableFragptr; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); tuxreq->tupTableFragPtrI[0] = tFragPtr.p->tupFragptr[0]; tuxreq->tupTableFragPtrI[1] = tFragPtr.p->tupFragptr[1]; tuxreq->accTableFragPtrI[0] = tFragPtr.p->accFragptr[0]; tuxreq->accTableFragPtrI[1] = tFragPtr.p->accFragptr[1]; sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, signal, TuxFragReq::SignalLength, JBB); return; } } ndbrequire(false); }//Dblqh::sendAddFragReq /* ************************************************************************> */ /* LQHADDATTRREQ: Request from DICT to create attributes for the new table. */ /* ************************************************************************> */ void Dblqh::execLQHADDATTREQ(Signal* signal) { jamEntry(); LqhAddAttrReq * const req = (LqhAddAttrReq*)signal->getDataPtr(); addfragptr.i = req->lqhFragPtr; const Uint32 tnoOfAttr = req->noOfAttributes; const Uint32 senderData = req->senderData; const Uint32 senderAttrPtr = req->senderAttrPtr; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::WAIT_ADD_ATTR); ndbrequire((tnoOfAttr != 0) && (tnoOfAttr <= LqhAddAttrReq::MAX_ATTRIBUTES)); addfragptr.p->totalAttrReceived += tnoOfAttr; ndbrequire(addfragptr.p->totalAttrReceived <= addfragptr.p->noOfAttr); addfragptr.p->attrReceived = tnoOfAttr; for (Uint32 i = 0; i < tnoOfAttr; i++) { addfragptr.p->attributes[i] = req->attributes[i]; }//for addfragptr.p->attrSentToTup = 0; ndbrequire(addfragptr.p->dictConnectptr == senderData); addfragptr.p->m_senderAttrPtr = senderAttrPtr; addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT1; sendAddAttrReq(signal); }//Dblqh::execLQHADDATTREQ() /* *********************>> */ /* TUP_ADD_ATTCONF > */ /* *********************>> */ void Dblqh::execTUP_ADD_ATTCONF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); switch (addfragptr.p->addfragStatus) { case AddFragRecord::TUP_ATTR_WAIT1: jam(); addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT2; sendAddAttrReq(signal); break; case AddFragRecord::TUP_ATTR_WAIT2: jam(); if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT1; sendAddAttrReq(signal); break; } goto done_with_attr; break; case AddFragRecord::TUX_ATTR_WAIT1: jam(); addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT2; sendAddAttrReq(signal); break; case AddFragRecord::TUX_ATTR_WAIT2: jam(); goto done_with_attr; break; done_with_attr: addfragptr.p->attrSentToTup = addfragptr.p->attrSentToTup + 1; ndbrequire(addfragptr.p->attrSentToTup <= addfragptr.p->attrReceived); ndbrequire(addfragptr.p->totalAttrReceived <= addfragptr.p->noOfAttr); if (addfragptr.p->attrSentToTup < addfragptr.p->attrReceived) { // more in this batch jam(); addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT1; sendAddAttrReq(signal); } else if (addfragptr.p->totalAttrReceived < addfragptr.p->noOfAttr) { // more batches to receive jam(); addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR; LqhAddAttrConf *const conf = (LqhAddAttrConf*)signal->getDataPtrSend(); conf->senderData = addfragptr.p->dictConnectptr; conf->senderAttrPtr = addfragptr.p->m_senderAttrPtr; conf->fragId = addfragptr.p->addFragid; sendSignal(addfragptr.p->dictBlockref, GSN_LQHADDATTCONF, signal, LqhAddAttrConf::SignalLength, JBB); } else { fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); /* ------------------------------------------------------------------ * WE HAVE NOW COMPLETED ADDING THIS FRAGMENT. WE NOW NEED TO SET THE * PROPER STATE IN FRAG_STATUS DEPENDENT ON IF WE ARE CREATING A NEW * REPLICA OR IF WE ARE CREATING A TABLE. FOR FRAGMENTS IN COPY * PROCESS WE DO NOT WANT LOGGING ACTIVATED. * ----------------------------------------------------------------- */ if (addfragptr.p->fragCopyCreation == 1) { jam(); if (! DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION; else fragptr.p->fragStatus = Fragrecord::FSACTIVE; fragptr.p->logFlag = Fragrecord::STATE_FALSE; } else { jam(); fragptr.p->fragStatus = Fragrecord::FSACTIVE; }//if LqhAddAttrConf *const conf = (LqhAddAttrConf*)signal->getDataPtrSend(); conf->senderData = addfragptr.p->dictConnectptr; conf->senderAttrPtr = addfragptr.p->m_senderAttrPtr; conf->fragId = addfragptr.p->addFragid; sendSignal(addfragptr.p->dictBlockref, GSN_LQHADDATTCONF, signal, LqhAddAttrConf::SignalLength, JBB); releaseAddfragrec(signal); }//if break; default: ndbrequire(false); break; } } /* **********************>> */ /* TUX_ADD_ATTRCONF > */ /* **********************>> */ void Dblqh::execTUX_ADD_ATTRCONF(Signal* signal) { jamEntry(); execTUP_ADD_ATTCONF(signal); }//Dblqh::execTUX_ADD_ATTRCONF /* * Add attribute in TUP or TUX. Called up to 4 times. */ void Dblqh::sendAddAttrReq(Signal* signal) { arrGuard(addfragptr.p->attrSentToTup, LqhAddAttrReq::MAX_ATTRIBUTES); LqhAddAttrReq::Entry& entry = addfragptr.p->attributes[addfragptr.p->attrSentToTup]; const Uint32 attrId = entry.attrId & 0xffff; const Uint32 primaryAttrId = entry.attrId >> 16; fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT1 || addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT2) { if (DictTabInfo::isTable(addfragptr.p->tableType) || DictTabInfo::isHashIndex(addfragptr.p->tableType) || (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && primaryAttrId == ZNIL)) { jam(); TupAddAttrReq* const tupreq = (TupAddAttrReq*)signal->getDataPtrSend(); tupreq->tupConnectPtr = addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT1 ? addfragptr.p->tup1Connectptr : addfragptr.p->tup2Connectptr; tupreq->notused1 = 0; tupreq->attrId = attrId; tupreq->attrDescriptor = entry.attrDescriptor; tupreq->extTypeInfo = entry.extTypeInfo; sendSignal(fragptr.p->tupBlockref, GSN_TUP_ADD_ATTRREQ, signal, TupAddAttrReq::SignalLength, JBB); return; } if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && primaryAttrId != ZNIL) { // this attribute is not for TUP jam(); TupAddAttrConf* tupconf = (TupAddAttrConf*)signal->getDataPtrSend(); tupconf->userPtr = addfragptr.i; sendSignal(reference(), GSN_TUP_ADD_ATTCONF, signal, TupAddAttrConf::SignalLength, JBB); return; } } if (addfragptr.p->addfragStatus == AddFragRecord::TUX_ATTR_WAIT1 || addfragptr.p->addfragStatus == AddFragRecord::TUX_ATTR_WAIT2) { jam(); if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && primaryAttrId != ZNIL) { jam(); TuxAddAttrReq* const tuxreq = (TuxAddAttrReq*)signal->getDataPtrSend(); tuxreq->tuxConnectPtr = addfragptr.p->addfragStatus == AddFragRecord::TUX_ATTR_WAIT1 ? addfragptr.p->tux1Connectptr : addfragptr.p->tux2Connectptr; tuxreq->notused1 = 0; tuxreq->attrId = attrId; tuxreq->attrDescriptor = entry.attrDescriptor; tuxreq->extTypeInfo = entry.extTypeInfo; tuxreq->primaryAttrId = primaryAttrId; sendSignal(fragptr.p->tuxBlockref, GSN_TUX_ADD_ATTRREQ, signal, TuxAddAttrReq::SignalLength, JBB); return; } if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && primaryAttrId == ZNIL) { // this attribute is not for TUX jam(); TuxAddAttrConf* tuxconf = (TuxAddAttrConf*)signal->getDataPtrSend(); tuxconf->userPtr = addfragptr.i; sendSignal(reference(), GSN_TUX_ADD_ATTRCONF, signal, TuxAddAttrConf::SignalLength, JBB); return; } } ndbrequire(false); }//Dblqh::sendAddAttrReq /* ************************************************************************>> */ /* TAB_COMMITREQ: Commit the new table for use in transactions. Sender DICT. */ /* ************************************************************************>> */ void Dblqh::execTAB_COMMITREQ(Signal* signal) { jamEntry(); Uint32 dihPtr = signal->theData[0]; BlockReference dihBlockref = signal->theData[1]; tabptr.i = signal->theData[2]; if (tabptr.i >= ctabrecFileSize) { jam(); terrorCode = ZTAB_FILE_SIZE; signal->theData[0] = dihPtr; signal->theData[1] = cownNodeid; signal->theData[2] = tabptr.i; signal->theData[3] = terrorCode; sendSignal(dihBlockref, GSN_TAB_COMMITREF, signal, 4, JBB); return; }//if ptrAss(tabptr, tablerec); if (tabptr.p->tableStatus != Tablerec::ADD_TABLE_ONGOING) { jam(); terrorCode = ZTAB_STATE_ERROR; signal->theData[0] = dihPtr; signal->theData[1] = cownNodeid; signal->theData[2] = tabptr.i; signal->theData[3] = terrorCode; signal->theData[4] = tabptr.p->tableStatus; sendSignal(dihBlockref, GSN_TAB_COMMITREF, signal, 5, JBB); ndbrequire(false); return; }//if tabptr.p->usageCount = 0; tabptr.p->tableStatus = Tablerec::TABLE_DEFINED; signal->theData[0] = dihPtr; signal->theData[1] = cownNodeid; signal->theData[2] = tabptr.i; sendSignal(dihBlockref, GSN_TAB_COMMITCONF, signal, 3, JBB); return; }//Dblqh::execTAB_COMMITREQ() void Dblqh::fragrefLab(Signal* signal, BlockReference fragBlockRef, Uint32 fragConPtr, Uint32 errorCode) { LqhFragRef * ref = (LqhFragRef*)signal->getDataPtrSend(); ref->senderData = fragConPtr; ref->errorCode = errorCode; sendSignal(fragBlockRef, GSN_LQHFRAGREF, signal, LqhFragRef::SignalLength, JBB); return; }//Dblqh::fragrefLab() /* ************>> */ /* ACCFRAGREF > */ /* ************>> */ void Dblqh::execACCFRAGREF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); terrorCode = signal->theData[1]; ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::ACC_ADDFRAG); addfragptr.p->addfragErrorCode = terrorCode; const Uint32 ref = addfragptr.p->dictBlockref; const Uint32 senderData = addfragptr.p->dictConnectptr; const Uint32 errorCode = addfragptr.p->addfragErrorCode; releaseAddfragrec(signal); fragrefLab(signal, ref, senderData, errorCode); return; }//Dblqh::execACCFRAGREF() /* ************>> */ /* TUPFRAGREF > */ /* ************>> */ void Dblqh::execTUPFRAGREF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); terrorCode = signal->theData[1]; fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); addfragptr.p->addfragErrorCode = terrorCode; const Uint32 ref = addfragptr.p->dictBlockref; const Uint32 senderData = addfragptr.p->dictConnectptr; const Uint32 errorCode = addfragptr.p->addfragErrorCode; releaseAddfragrec(signal); fragrefLab(signal, ref, senderData, errorCode); }//Dblqh::execTUPFRAGREF() /* ************>> */ /* TUXFRAGREF > */ /* ************>> */ void Dblqh::execTUXFRAGREF(Signal* signal) { jamEntry(); execTUPFRAGREF(signal); }//Dblqh::execTUXFRAGREF /* *********************> */ /* TUP_ADD_ATTREF > */ /* *********************> */ void Dblqh::execTUP_ADD_ATTRREF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); terrorCode = signal->theData[1]; addfragptr.p->addfragErrorCode = terrorCode; const Uint32 Ref = addfragptr.p->dictBlockref; const Uint32 senderData = addfragptr.p->dictConnectptr; const Uint32 errorCode = addfragptr.p->addfragErrorCode; releaseAddfragrec(signal); LqhAddAttrRef *const ref = (LqhAddAttrRef*)signal->getDataPtrSend(); ref->senderData = senderData; ref->errorCode = errorCode; sendSignal(Ref, GSN_LQHADDATTREF, signal, LqhAddAttrRef::SignalLength, JBB); }//Dblqh::execTUP_ADD_ATTRREF() /* **********************> */ /* TUX_ADD_ATTRREF > */ /* **********************> */ void Dblqh::execTUX_ADD_ATTRREF(Signal* signal) { jamEntry(); execTUP_ADD_ATTRREF(signal); }//Dblqh::execTUX_ADD_ATTRREF void Dblqh::execPREP_DROP_TAB_REQ(Signal* signal){ jamEntry(); PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); Uint32 senderRef = req->senderRef; Uint32 senderData = req->senderData; TablerecPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); Uint32 errCode = 0; errCode = checkDropTabState(tabPtr.p->tableStatus, GSN_PREP_DROP_TAB_REQ); if(errCode != 0){ jam(); PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = errCode; sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal, PrepDropTabRef::SignalLength, JBB); return; } tabPtr.p->tableStatus = Tablerec::PREP_DROP_TABLE_ONGOING; tabPtr.p->waitingTC.clear(); tabPtr.p->waitingDIH.clear(); PrepDropTabConf * conf = (PrepDropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); conf->senderData = senderData; sendSignal(senderRef, GSN_PREP_DROP_TAB_CONF, signal, PrepDropTabConf::SignalLength, JBB); signal->theData[0] = ZPREP_DROP_TABLE; signal->theData[1] = tabPtr.i; signal->theData[2] = senderRef; signal->theData[3] = senderData; checkDropTab(signal); } void Dblqh::checkDropTab(Signal* signal){ TablerecPtr tabPtr; tabPtr.i = signal->theData[1]; ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); ndbrequire(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING); if(tabPtr.p->usageCount > 0){ jam(); sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 4); return; } bool lcpDone = true; lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); if(lcpPtr.p->lcpState != LcpRecord::LCP_IDLE){ jam(); if(lcpPtr.p->currentFragment.lcpFragOrd.tableId == tabPtr.i){ jam(); lcpDone = false; } if(lcpPtr.p->lcpQueued && lcpPtr.p->queuedFragment.lcpFragOrd.tableId == tabPtr.i){ jam(); lcpDone = false; } } if(!lcpDone){ jam(); sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 4); return; } tabPtr.p->tableStatus = Tablerec::PREP_DROP_TABLE_DONE; WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); for(Uint32 i = 1; i<MAX_NDB_NODES; i++){ if(tabPtr.p->waitingTC.get(i)){ tabPtr.p->waitingTC.clear(i); sendSignal(calcTcBlockRef(i), GSN_WAIT_DROP_TAB_CONF, signal, WaitDropTabConf::SignalLength, JBB); } if(tabPtr.p->waitingDIH.get(i)){ tabPtr.p->waitingDIH.clear(i); sendSignal(calcDihBlockRef(i), GSN_WAIT_DROP_TAB_CONF, signal, WaitDropTabConf::SignalLength, JBB); } } } void Dblqh::execWAIT_DROP_TAB_REQ(Signal* signal){ jamEntry(); WaitDropTabReq * req = (WaitDropTabReq*)signal->getDataPtr(); TablerecPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); Uint32 senderRef = req->senderRef; Uint32 nodeId = refToNode(senderRef); Uint32 blockNo = refToBlock(senderRef); if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING){ jam(); switch(blockNo){ case DBTC: tabPtr.p->waitingTC.set(nodeId); break; case DBDIH: tabPtr.p->waitingDIH.set(nodeId); break; default: ndbrequire(false); } return; } if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ jam(); WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtrSend(); conf->tableId = tabPtr.i; conf->senderRef = reference(); sendSignal(senderRef, GSN_WAIT_DROP_TAB_CONF, signal, WaitDropTabConf::SignalLength, JBB); return; } WaitDropTabRef * ref = (WaitDropTabRef*)signal->getDataPtrSend(); ref->tableId = tabPtr.i; ref->senderRef = reference(); bool ok = false; switch(tabPtr.p->tableStatus){ case Tablerec::TABLE_DEFINED: ok = true; ref->errorCode = WaitDropTabRef::IllegalTableState; break; case Tablerec::NOT_DEFINED: ok = true; ref->errorCode = WaitDropTabRef::NoSuchTable; break; case Tablerec::ADD_TABLE_ONGOING: ok = true; ref->errorCode = WaitDropTabRef::IllegalTableState; break; case Tablerec::PREP_DROP_TABLE_ONGOING: case Tablerec::PREP_DROP_TABLE_DONE: // Should have been take care of above ndbrequire(false); } ndbrequire(ok); ref->tableStatus = tabPtr.p->tableStatus; sendSignal(senderRef, GSN_WAIT_DROP_TAB_REF, signal, WaitDropTabRef::SignalLength, JBB); return; } void Dblqh::execDROP_TAB_REQ(Signal* signal){ jamEntry(); DropTabReq* req = (DropTabReq*)signal->getDataPtr(); Uint32 senderRef = req->senderRef; Uint32 senderData = req->senderData; TablerecPtr tabPtr; tabPtr.i = req->tableId; ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); do { if(req->requestType == DropTabReq::RestartDropTab){ jam(); break; } if(req->requestType == DropTabReq::OnlineDropTab){ jam(); Uint32 errCode = 0; errCode = checkDropTabState(tabPtr.p->tableStatus, GSN_DROP_TAB_REQ); if(errCode != 0){ jam(); DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend(); ref->senderRef = reference(); ref->senderData = senderData; ref->tableId = tabPtr.i; ref->errorCode = errCode; sendSignal(senderRef, GSN_DROP_TAB_REF, signal, DropTabRef::SignalLength, JBB); return; } } removeTable(tabPtr.i); } while(false); ndbrequire(tabPtr.p->usageCount == 0); tabPtr.p->tableStatus = Tablerec::NOT_DEFINED; DropTabConf * const dropConf = (DropTabConf *)signal->getDataPtrSend(); dropConf->senderRef = reference(); dropConf->senderData = senderData; dropConf->tableId = tabPtr.i; sendSignal(senderRef, GSN_DROP_TAB_CONF, signal, DropTabConf::SignalLength, JBB); } Uint32 Dblqh::checkDropTabState(Tablerec::TableStatus status, Uint32 gsn) const{ if(gsn == GSN_PREP_DROP_TAB_REQ){ switch(status){ case Tablerec::NOT_DEFINED: jam(); // Fall through case Tablerec::ADD_TABLE_ONGOING: jam(); return PrepDropTabRef::NoSuchTable; break; case Tablerec::PREP_DROP_TABLE_ONGOING: jam(); return PrepDropTabRef::PrepDropInProgress; break; case Tablerec::PREP_DROP_TABLE_DONE: jam(); return PrepDropTabRef::DropInProgress; break; case Tablerec::TABLE_DEFINED: jam(); return 0; break; } ndbrequire(0); } if(gsn == GSN_DROP_TAB_REQ){ switch(status){ case Tablerec::NOT_DEFINED: jam(); // Fall through case Tablerec::ADD_TABLE_ONGOING: jam(); return DropTabRef::NoSuchTable; break; case Tablerec::PREP_DROP_TABLE_ONGOING: jam(); return DropTabRef::PrepDropInProgress; break; case Tablerec::PREP_DROP_TABLE_DONE: jam(); return 0; break; case Tablerec::TABLE_DEFINED: jam(); return DropTabRef::DropWoPrep; } ndbrequire(0); } ndbrequire(0); return RNIL; } void Dblqh::removeTable(Uint32 tableId) { tabptr.i = tableId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { jam(); if (tabptr.p->fragid[i] != ZNIL) { jam(); deleteFragrec(tabptr.p->fragid[i]); }//if }//for }//Dblqh::removeTable() void Dblqh::execALTER_TAB_REQ(Signal* signal) { jamEntry(); 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; TablerecPtr tablePtr; tablePtr.i = tableId; ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec); tablePtr.p->schemaVersion = 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); } /* ************************************************************************>> * TIME_SIGNAL: Handles time-out of local operations. This is a clean-up * handler. If no other measure has succeeded in cleaning up after time-outs * or else then this routine will remove the transaction after 120 seconds of * inactivity. The check is performed once per 10 second. Sender is QMGR. * ************************************************************************>> */ void Dblqh::execTIME_SIGNAL(Signal* signal) { jamEntry(); cLqhTimeOutCount++; cLqhTimeOutCheckCount++; if ((cCounterAccCommitBlocked > 0) || (cCounterTupCommitBlocked > 0)) { jam(); signal->theData[0] = EventReport::UndoLogBlocked; signal->theData[1] = cCounterTupCommitBlocked; signal->theData[2] = cCounterAccCommitBlocked; sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB); cCounterTupCommitBlocked = 0; cCounterAccCommitBlocked = 0; }//if if (cLqhTimeOutCheckCount < 10) { jam(); return; }//if cLqhTimeOutCheckCount = 0; #ifdef VM_TRACE TcConnectionrecPtr tTcConptr; for (tTcConptr.i = 0; tTcConptr.i < ctcConnectrecFileSize; tTcConptr.i++) { jam(); ptrAss(tTcConptr, tcConnectionrec); if ((tTcConptr.p->tcTimer != 0) && ((tTcConptr.p->tcTimer + 120) < cLqhTimeOutCount)) { ndbout << "Dblqh::execTIME_SIGNAL"<<endl << "Timeout found in tcConnectRecord " <<tTcConptr.i<<endl << " cLqhTimeOutCount = " << cLqhTimeOutCount << endl << " tcTimer="<<tTcConptr.p->tcTimer<<endl << " tcTimer+120="<<tTcConptr.p->tcTimer + 120<<endl; ndbout << " transactionState = " << tTcConptr.p->transactionState<<endl; ndbout << " operation = " << tTcConptr.p->operation<<endl; ndbout << " tcNodeFailrec = " << tTcConptr.p->tcNodeFailrec << " seqNoReplica = " << tTcConptr.p->seqNoReplica << " simpleRead = " << tTcConptr.p->simpleRead << endl; ndbout << " replicaType = " << tTcConptr.p->replicaType << " reclenAiLqhkey = " << tTcConptr.p->reclenAiLqhkey << " opExec = " << tTcConptr.p->opExec << endl; ndbout << " opSimple = " << tTcConptr.p->opSimple << " nextSeqNoReplica = " << tTcConptr.p->nextSeqNoReplica << " lockType = " << tTcConptr.p->lockType << " localFragptr = " << tTcConptr.p->localFragptr << endl; ndbout << " lastReplicaNo = " << tTcConptr.p->lastReplicaNo << " indTakeOver = " << tTcConptr.p->indTakeOver << " dirtyOp = " << tTcConptr.p->dirtyOp << endl; ndbout << " activeCreat = " << tTcConptr.p->activeCreat << " tcBlockref = " << hex << tTcConptr.p->tcBlockref << " reqBlockref = " << hex << tTcConptr.p->reqBlockref << " primKeyLen = " << tTcConptr.p->primKeyLen << endl; ndbout << " nextReplica = " << tTcConptr.p->nextReplica << " tcBlockref = " << hex << tTcConptr.p->tcBlockref << " reqBlockref = " << hex << tTcConptr.p->reqBlockref << " primKeyLen = " << tTcConptr.p->primKeyLen << endl; ndbout << " logStopPageNo = " << tTcConptr.p->logStopPageNo << " logStartPageNo = " << tTcConptr.p->logStartPageNo << " logStartPageIndex = " << tTcConptr.p->logStartPageIndex << endl; ndbout << " errorCode = " << tTcConptr.p->errorCode << " clientBlockref = " << hex << tTcConptr.p->clientBlockref << " applRef = " << hex << tTcConptr.p->applRef << " totSendlenAi = " << tTcConptr.p->totSendlenAi << endl; ndbout << " totReclenAi = " << tTcConptr.p->totReclenAi << " tcScanRec = " << tTcConptr.p->tcScanRec << " tcScanInfo = " << tTcConptr.p->tcScanInfo << " tcOprec = " << hex << tTcConptr.p->tcOprec << endl; ndbout << " tableref = " << tTcConptr.p->tableref << " simpleTcConnect = " << tTcConptr.p->simpleTcConnect << " storedProcId = " << tTcConptr.p->storedProcId << " schemaVersion = " << tTcConptr.p->schemaVersion << endl; ndbout << " reqinfo = " << tTcConptr.p->reqinfo << " reqRef = " << tTcConptr.p->reqRef << " readlenAi = " << tTcConptr.p->readlenAi << " prevTc = " << tTcConptr.p->prevTc << endl; ndbout << " prevLogTcrec = " << tTcConptr.p->prevLogTcrec << " prevHashRec = " << tTcConptr.p->prevHashRec << " nodeAfterNext0 = " << tTcConptr.p->nodeAfterNext[0] << " nodeAfterNext1 = " << tTcConptr.p->nodeAfterNext[1] << endl; ndbout << " nextTcConnectrec = " << tTcConptr.p->nextTcConnectrec << " nextTc = " << tTcConptr.p->nextTc << " nextTcLogQueue = " << tTcConptr.p->nextTcLogQueue << " nextLogTcrec = " << tTcConptr.p->nextLogTcrec << endl; ndbout << " nextHashRec = " << tTcConptr.p->nextHashRec << " logWriteState = " << tTcConptr.p->logWriteState << " logStartFileNo = " << tTcConptr.p->logStartFileNo << " listState = " << tTcConptr.p->listState << endl; ndbout << " lastAttrinbuf = " << tTcConptr.p->lastAttrinbuf << " lastTupkeybuf = " << tTcConptr.p->lastTupkeybuf << " hashValue = " << tTcConptr.p->hashValue << endl; ndbout << " gci = " << tTcConptr.p->gci << " fragmentptr = " << tTcConptr.p->fragmentptr << " fragmentid = " << tTcConptr.p->fragmentid << " firstTupkeybuf = " << tTcConptr.p->firstTupkeybuf << endl; ndbout << " firstAttrinbuf = " << tTcConptr.p->firstAttrinbuf << " currTupAiLen = " << tTcConptr.p->currTupAiLen << " currReclenAi = " << tTcConptr.p->currReclenAi << endl; ndbout << " tcTimer = " << tTcConptr.p->tcTimer << " clientConnectrec = " << tTcConptr.p->clientConnectrec << " applOprec = " << hex << tTcConptr.p->applOprec << " abortState = " << tTcConptr.p->abortState << endl; ndbout << " transid0 = " << hex << tTcConptr.p->transid[0] << " transid1 = " << hex << tTcConptr.p->transid[1] << " tupkeyData0 = " << tTcConptr.p->tupkeyData[0] << " tupkeyData1 = " << tTcConptr.p->tupkeyData[1] << endl; ndbout << " tupkeyData2 = " << tTcConptr.p->tupkeyData[2] << " tupkeyData3 = " << tTcConptr.p->tupkeyData[3] << endl; switch (tTcConptr.p->transactionState) { case TcConnectionrec::SCAN_STATE_USED: if (tTcConptr.p->tcScanRec < cscanrecFileSize){ ScanRecordPtr TscanPtr; c_scanRecordPool.getPtr(TscanPtr, tTcConptr.p->tcScanRec); ndbout << " scanState = " << TscanPtr.p->scanState << endl; //TscanPtr.p->scanLocalref[2]; ndbout << " copyPtr="<<TscanPtr.p->copyPtr << " scanAccPtr="<<TscanPtr.p->scanAccPtr << " scanAiLength="<<TscanPtr.p->scanAiLength << endl; ndbout << " m_curr_batch_size_rows="<< TscanPtr.p->m_curr_batch_size_rows << " m_max_batch_size_rows="<< TscanPtr.p->m_max_batch_size_rows << " scanErrorCounter="<<TscanPtr.p->scanErrorCounter << " scanLocalFragid="<<TscanPtr.p->scanLocalFragid << endl; ndbout << " scanSchemaVersion="<<TscanPtr.p->scanSchemaVersion << " scanStoredProcId="<<TscanPtr.p->scanStoredProcId << " scanTcrec="<<TscanPtr.p->scanTcrec << endl; ndbout << " scanType="<<TscanPtr.p->scanType << " scanApiBlockref="<<TscanPtr.p->scanApiBlockref << " scanNodeId="<<TscanPtr.p->scanNodeId << " scanCompletedStatus="<<TscanPtr.p->scanCompletedStatus << endl; ndbout << " scanFlag="<<TscanPtr.p->scanFlag << " scanLockHold="<<TscanPtr.p->scanLockHold << " scanLockMode="<<TscanPtr.p->scanLockMode << " scanNumber="<<TscanPtr.p->scanNumber << endl; ndbout << " scanReleaseCounter="<<TscanPtr.p->scanReleaseCounter << " scanTcWaiting="<<TscanPtr.p->scanTcWaiting << " scanKeyinfoFlag="<<TscanPtr.p->scanKeyinfoFlag << endl; }else{ ndbout << "No connected scan record found" << endl; } break; default: break; }//switch // Reset the timer tTcConptr.p->tcTimer = 0; }//if }//for #endif #ifdef VM_TRACE for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) { ptrAss(lfoPtr, logFileOperationRecord); if ((lfoPtr.p->lfoTimer != 0) && ((lfoPtr.p->lfoTimer + 120) < cLqhTimeOutCount)) { ndbout << "We have lost LFO record" << endl; ndbout << "index = " << lfoPtr.i; ndbout << "State = " << lfoPtr.p->lfoState; ndbout << " Page No = " << lfoPtr.p->lfoPageNo; ndbout << " noPagesRw = " << lfoPtr.p->noPagesRw; ndbout << "lfoWordWritten = " << lfoPtr.p->lfoWordWritten << endl; lfoPtr.p->lfoTimer = cLqhTimeOutCount; }//if }//for #endif #if 0 LcpRecordPtr TlcpPtr; // Print information about the current local checkpoint TlcpPtr.i = 0; ptrAss(TlcpPtr, lcpRecord); ndbout << "Information about LCP in this LQH" << endl << " lcpState="<<TlcpPtr.p->lcpState<<endl << " firstLcpLocAcc="<<TlcpPtr.p->firstLcpLocAcc<<endl << " firstLcpLocTup="<<TlcpPtr.p->firstLcpLocTup<<endl << " lcpAccptr="<<TlcpPtr.p->lcpAccptr<<endl << " lastFragmentFlag="<<TlcpPtr.p->lastFragmentFlag<<endl << " lcpQueued="<<TlcpPtr.p->lcpQueued<<endl << " reportEmptyref="<< TlcpPtr.p->reportEmptyRef<<endl << " reportEmpty="<<TlcpPtr.p->reportEmpty<<endl; #endif }//Dblqh::execTIME_SIGNAL() /* ######################################################################### */ /* ####### EXECUTION MODULE ####### */ /* THIS MODULE HANDLES THE RECEPTION OF LQHKEYREQ AND ALL PROCESSING */ /* OF OPERATIONS ON BEHALF OF THIS REQUEST. THIS DOES ALSO INVOLVE */ /* RECEPTION OF VARIOUS TYPES OF ATTRINFO AND KEYINFO. IT DOES ALSO */ /* INVOLVE COMMUNICATION WITH ACC AND TUP. */ /* ######################################################################### */ void Dblqh::noFreeRecordLab(Signal* signal, const LqhKeyReq * lqhKeyReq, Uint32 errCode) { jamEntry(); const Uint32 transid1 = lqhKeyReq->transId1; const Uint32 transid2 = lqhKeyReq->transId2; const Uint32 reqInfo = lqhKeyReq->requestInfo; if(errCode == ZNO_FREE_MARKER_RECORDS_ERROR || errCode == ZNODE_SHUTDOWN_IN_PROGESS){ releaseTcrec(signal, tcConnectptr); } if (LqhKeyReq::getSimpleFlag(reqInfo) && LqhKeyReq::getOperation(reqInfo) == ZREAD){ jam(); ndbrequire(LqhKeyReq::getApplicationAddressFlag(reqInfo)); const Uint32 apiRef = lqhKeyReq->variableData[0]; const Uint32 apiOpRec = lqhKeyReq->variableData[1]; TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); tcKeyRef->connectPtr = apiOpRec; tcKeyRef->transId[0] = transid1; tcKeyRef->transId[1] = transid2; tcKeyRef->errorCode = errCode; sendSignal(apiRef, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); } else { jam(); const Uint32 clientPtr = lqhKeyReq->clientConnectPtr; Uint32 TcOprec = clientPtr; if(LqhKeyReq::getSameClientAndTcFlag(reqInfo) == 1){ if(LqhKeyReq::getApplicationAddressFlag(reqInfo)) TcOprec = lqhKeyReq->variableData[2]; else TcOprec = lqhKeyReq->variableData[0]; } LqhKeyRef * const ref = (LqhKeyRef*)signal->getDataPtrSend(); ref->userRef = clientPtr; ref->connectPtr = TcOprec; ref->errorCode = errCode; ref->transId1 = transid1; ref->transId2 = transid2; sendSignal(signal->senderBlockRef(), GSN_LQHKEYREF, signal, LqhKeyRef::SignalLength, JBB); }//if return; }//Dblqh::noFreeRecordLab() void Dblqh::LQHKEY_abort(Signal* signal, int errortype) { switch (errortype) { case 0: jam(); terrorCode = ZCOPY_NODE_ERROR; break; case 1: jam(); terrorCode = ZNO_FREE_LQH_CONNECTION; break; case 2: jam(); terrorCode = signal->theData[1]; break; case 3: jam(); ndbrequire((tcConnectptr.p->transactionState == TcConnectionrec::WAIT_ACC_ABORT) || (tcConnectptr.p->transactionState == TcConnectionrec::ABORT_STOPPED) || (tcConnectptr.p->transactionState == TcConnectionrec::ABORT_QUEUED)); return; break; case 4: jam(); if(tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ jam(); terrorCode = ZTABLE_NOT_DEFINED; } else if (tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ jam(); terrorCode = ZDROP_TABLE_IN_PROGRESS; } else { ndbrequire(0); } break; case 5: jam(); terrorCode = ZINVALID_SCHEMA_VERSION; break; default: ndbrequire(false); break; }//switch abortErrorLab(signal); }//Dblqh::LQHKEY_abort() void Dblqh::LQHKEY_error(Signal* signal, int errortype) { switch (errortype) { case 0: jam(); break; case 1: jam(); break; case 2: jam(); break; case 3: jam(); break; case 4: jam(); break; case 5: jam(); break; case 6: jam(); break; default: jam(); break; }//switch ndbrequire(false); }//Dblqh::LQHKEY_error() void Dblqh::execLQHKEYREF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; terrorCode = signal->theData[2]; Uint32 transid1 = signal->theData[3]; Uint32 transid2 = signal->theData[4]; if (tcConnectptr.i >= ctcConnectrecFileSize) { errorReport(signal, 3); return; }//if /*------------------------------------------------------------------*/ /* WE HAVE TO CHECK THAT THE SIGNAL DO NOT BELONG TO SOMETHING*/ /* REMOVED DUE TO A TIME-OUT. */ /*------------------------------------------------------------------*/ ptrAss(tcConnectptr, tcConnectionrec); TcConnectionrec * const regTcPtr = tcConnectptr.p; switch (regTcPtr->connectState) { case TcConnectionrec::CONNECTED: jam(); if ((regTcPtr->transid[0] != transid1) || (regTcPtr->transid[1] != transid2)) { warningReport(signal, 14); return; }//if if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { warningReport(signal, 15); return; }//if abortErrorLab(signal); return; break; case TcConnectionrec::LOG_CONNECTED: jam(); logLqhkeyrefLab(signal); return; break; case TcConnectionrec::COPY_CONNECTED: jam(); copyLqhKeyRefLab(signal); return; break; default: warningReport(signal, 16); return; break; }//switch }//Dblqh::execLQHKEYREF() /* -------------------------------------------------------------------------- */ /* ------- ENTER PACKED_SIGNAL ------- */ /* Execution of packed signal. The packed signal can contain COMMIT, COMPLETE */ /* or LQHKEYCONF signals. These signals will be executed by their resp. exec */ /* functions. */ /* -------------------------------------------------------------------------- */ void Dblqh::execPACKED_SIGNAL(Signal* signal) { Uint32 Tstep = 0; Uint32 Tlength; Uint32 TpackedData[28]; Uint32 sig0, sig1, sig2, sig3 ,sig4, sig5, sig6; jamEntry(); Tlength = signal->length(); ndbrequire(Tlength <= 25); MEMCOPY_NO_WORDS(&TpackedData[0], &signal->theData[0], Tlength); while (Tlength > Tstep) { switch (TpackedData[Tstep] >> 28) { case ZCOMMIT: jam(); sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; sig1 = TpackedData[Tstep + 1]; sig2 = TpackedData[Tstep + 2]; sig3 = TpackedData[Tstep + 3]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->theData[2] = sig2; signal->theData[3] = sig3; signal->header.theLength = 4; execCOMMIT(signal); Tstep += 4; break; case ZCOMPLETE: jam(); sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; sig1 = TpackedData[Tstep + 1]; sig2 = TpackedData[Tstep + 2]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->theData[2] = sig2; signal->header.theLength = 3; execCOMPLETE(signal); Tstep += 3; break; case ZLQHKEYCONF: { jam(); LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; sig1 = TpackedData[Tstep + 1]; sig2 = TpackedData[Tstep + 2]; sig3 = TpackedData[Tstep + 3]; sig4 = TpackedData[Tstep + 4]; sig5 = TpackedData[Tstep + 5]; sig6 = TpackedData[Tstep + 6]; lqhKeyConf->connectPtr = sig0; lqhKeyConf->opPtr = sig1; lqhKeyConf->userRef = sig2; lqhKeyConf->readLen = sig3; lqhKeyConf->transId1 = sig4; lqhKeyConf->transId2 = sig5; lqhKeyConf->noFiredTriggers = sig6; execLQHKEYCONF(signal); Tstep += LqhKeyConf::SignalLength; break; } case ZREMOVE_MARKER: jam(); sig0 = TpackedData[Tstep + 1]; sig1 = TpackedData[Tstep + 2]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->header.theLength = 2; execREMOVE_MARKER_ORD(signal); Tstep += 3; break; default: ndbrequire(false); return; }//switch }//while ndbrequire(Tlength == Tstep); return; }//Dblqh::execPACKED_SIGNAL() void Dblqh::execREMOVE_MARKER_ORD(Signal* signal) { CommitAckMarker key; key.transid1 = signal->theData[0]; key.transid2 = signal->theData[1]; jamEntry(); CommitAckMarkerPtr removedPtr; m_commitAckMarkerHash.release(removedPtr, key); ndbrequire(removedPtr.i != RNIL); #ifdef MARKER_TRACE ndbout_c("Rem marker[%.8x %.8x]", key.transid1, key.transid2); #endif } /* -------------------------------------------------------------------------- */ /* ------- ENTER SEND_PACKED ------- */ /* Used to force a packed signal to be sent if local signal buffer is not */ /* empty. */ /* -------------------------------------------------------------------------- */ void Dblqh::execSEND_PACKED(Signal* signal) { HostRecordPtr Thostptr; UintR i; UintR TpackedListIndex = cpackedListIndex; jamEntry(); for (i = 0; i < TpackedListIndex; i++) { Thostptr.i = cpackedList[i]; ptrAss(Thostptr, hostRecord); jam(); ndbrequire(Thostptr.i - 1 < MAX_NDB_NODES - 1); if (Thostptr.p->noOfPackedWordsLqh > 0) { jam(); sendPackedSignalLqh(signal, Thostptr.p); }//if if (Thostptr.p->noOfPackedWordsTc > 0) { jam(); sendPackedSignalTc(signal, Thostptr.p); }//if Thostptr.p->inPackedList = false; }//for cpackedListIndex = 0; return; }//Dblqh::execSEND_PACKED() void Dblqh::updatePackedList(Signal* signal, HostRecord * ahostptr, Uint16 hostId) { Uint32 TpackedListIndex = cpackedListIndex; if (ahostptr->inPackedList == false) { jam(); ahostptr->inPackedList = true; cpackedList[TpackedListIndex] = hostId; cpackedListIndex = TpackedListIndex + 1; }//if }//Dblqh::updatePackedList() void Dblqh::execREAD_PSUEDO_REQ(Signal* signal){ jamEntry(); TcConnectionrecPtr regTcPtr; regTcPtr.i = signal->theData[0]; ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec); FragrecordPtr regFragptr; regFragptr.i = regTcPtr.p->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); signal->theData[0] = regFragptr.p->accFragptr[regTcPtr.p->localFragptr]; EXECUTE_DIRECT(DBACC, GSN_READ_PSUEDO_REQ, signal, 2); } /* ************>> */ /* TUPKEYCONF > */ /* ************>> */ void Dblqh::execTUPKEYCONF(Signal* signal) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr(); Uint32 tcIndex = tupKeyConf->userPtr; jamEntry(); tcConnectptr.i = tcIndex; ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); if (tcConnectptr.p->seqNoReplica == 0) // Primary replica tcConnectptr.p->noFiredTriggers = tupKeyConf->noFiredTriggers; switch (tcConnectptr.p->transactionState) { case TcConnectionrec::WAIT_TUP: jam(); tupkeyConfLab(signal); break; case TcConnectionrec::COPY_TUPKEY: jam(); copyTupkeyConfLab(signal); break; case TcConnectionrec::SCAN_TUPKEY: jam(); scanTupkeyConfLab(signal); break; case TcConnectionrec::WAIT_TUP_TO_ABORT: jam(); /* ------------------------------------------------------------------------- */ // Abort was not ready to start until this signal came back. Now we are ready // to start the abort. /* ------------------------------------------------------------------------- */ releaseActiveFrag(signal); abortCommonLab(signal); break; case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::ABORT_QUEUED: jam(); /* -------------------------------------------------------------------------- */ /* IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ /* -------------------------------------------------------------------------- */ break; default: ndbrequire(false); break; }//switch }//Dblqh::execTUPKEYCONF() /* ************> */ /* TUPKEYREF > */ /* ************> */ void Dblqh::execTUPKEYREF(Signal* signal) { const TupKeyRef * const tupKeyRef = (TupKeyRef *)signal->getDataPtr(); jamEntry(); tcConnectptr.i = tupKeyRef->userRef; terrorCode = tupKeyRef->errorCode; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); switch (tcConnectptr.p->transactionState) { case TcConnectionrec::WAIT_TUP: jam(); releaseActiveFrag(signal); abortErrorLab(signal); break; case TcConnectionrec::COPY_TUPKEY: ndbrequire(false); break; case TcConnectionrec::SCAN_TUPKEY: jam(); scanTupkeyRefLab(signal); break; case TcConnectionrec::WAIT_TUP_TO_ABORT: jam(); /* ------------------------------------------------------------------------- */ // Abort was not ready to start until this signal came back. Now we are ready // to start the abort. /* ------------------------------------------------------------------------- */ releaseActiveFrag(signal); abortCommonLab(signal); break; case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::ABORT_QUEUED: jam(); /* ------------------------------------------------------------------------- */ /* IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ /* ------------------------------------------------------------------------- */ break; default: ndbrequire(false); break; }//switch }//Dblqh::execTUPKEYREF() void Dblqh::sendPackedSignalLqh(Signal* signal, HostRecord * ahostptr) { Uint32 noOfWords = ahostptr->noOfPackedWordsLqh; BlockReference hostRef = ahostptr->hostLqhBlockRef; MEMCOPY_NO_WORDS(&signal->theData[0], &ahostptr->packedWordsLqh[0], noOfWords); sendSignal(hostRef, GSN_PACKED_SIGNAL, signal, noOfWords, JBB); ahostptr->noOfPackedWordsLqh = 0; }//Dblqh::sendPackedSignalLqh() void Dblqh::sendPackedSignalTc(Signal* signal, HostRecord * ahostptr) { Uint32 noOfWords = ahostptr->noOfPackedWordsTc; BlockReference hostRef = ahostptr->hostTcBlockRef; MEMCOPY_NO_WORDS(&signal->theData[0], &ahostptr->packedWordsTc[0], noOfWords); sendSignal(hostRef, GSN_PACKED_SIGNAL, signal, noOfWords, JBB); ahostptr->noOfPackedWordsTc = 0; }//Dblqh::sendPackedSignalTc() void Dblqh::sendCommitLqh(Signal* signal, BlockReference alqhBlockref) { HostRecordPtr Thostptr; Thostptr.i = refToNode(alqhBlockref); ptrCheckGuard(Thostptr, chostFileSize, hostRecord); if (Thostptr.p->noOfPackedWordsLqh > 21) { jam(); sendPackedSignalLqh(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if Uint32 pos = Thostptr.p->noOfPackedWordsLqh; Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMMIT << 28); Uint32 gci = tcConnectptr.p->gci; Uint32 transid1 = tcConnectptr.p->transid[0]; Uint32 transid2 = tcConnectptr.p->transid[1]; Thostptr.p->packedWordsLqh[pos] = ptrAndType; Thostptr.p->packedWordsLqh[pos + 1] = gci; Thostptr.p->packedWordsLqh[pos + 2] = transid1; Thostptr.p->packedWordsLqh[pos + 3] = transid2; Thostptr.p->noOfPackedWordsLqh = pos + 4; }//Dblqh::sendCommitLqh() void Dblqh::sendCompleteLqh(Signal* signal, BlockReference alqhBlockref) { HostRecordPtr Thostptr; Thostptr.i = refToNode(alqhBlockref); ptrCheckGuard(Thostptr, chostFileSize, hostRecord); if (Thostptr.p->noOfPackedWordsLqh > 22) { jam(); sendPackedSignalLqh(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if Uint32 pos = Thostptr.p->noOfPackedWordsLqh; Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMPLETE << 28); Uint32 transid1 = tcConnectptr.p->transid[0]; Uint32 transid2 = tcConnectptr.p->transid[1]; Thostptr.p->packedWordsLqh[pos] = ptrAndType; Thostptr.p->packedWordsLqh[pos + 1] = transid1; Thostptr.p->packedWordsLqh[pos + 2] = transid2; Thostptr.p->noOfPackedWordsLqh = pos + 3; }//Dblqh::sendCompleteLqh() void Dblqh::sendCommittedTc(Signal* signal, BlockReference atcBlockref) { HostRecordPtr Thostptr; Thostptr.i = refToNode(atcBlockref); ptrCheckGuard(Thostptr, chostFileSize, hostRecord); if (Thostptr.p->noOfPackedWordsTc > 22) { jam(); sendPackedSignalTc(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if Uint32 pos = Thostptr.p->noOfPackedWordsTc; Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMMITTED << 28); Uint32 transid1 = tcConnectptr.p->transid[0]; Uint32 transid2 = tcConnectptr.p->transid[1]; Thostptr.p->packedWordsTc[pos] = ptrAndType; Thostptr.p->packedWordsTc[pos + 1] = transid1; Thostptr.p->packedWordsTc[pos + 2] = transid2; Thostptr.p->noOfPackedWordsTc = pos + 3; }//Dblqh::sendCommittedTc() void Dblqh::sendCompletedTc(Signal* signal, BlockReference atcBlockref) { HostRecordPtr Thostptr; Thostptr.i = refToNode(atcBlockref); ptrCheckGuard(Thostptr, chostFileSize, hostRecord); if (Thostptr.p->noOfPackedWordsTc > 22) { jam(); sendPackedSignalTc(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if Uint32 pos = Thostptr.p->noOfPackedWordsTc; Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMPLETED << 28); Uint32 transid1 = tcConnectptr.p->transid[0]; Uint32 transid2 = tcConnectptr.p->transid[1]; Thostptr.p->packedWordsTc[pos] = ptrAndType; Thostptr.p->packedWordsTc[pos + 1] = transid1; Thostptr.p->packedWordsTc[pos + 2] = transid2; Thostptr.p->noOfPackedWordsTc = pos + 3; }//Dblqh::sendCompletedTc() void Dblqh::sendLqhkeyconfTc(Signal* signal, BlockReference atcBlockref) { LqhKeyConf* lqhKeyConf; HostRecordPtr Thostptr; Thostptr.i = refToNode(atcBlockref); ptrCheckGuard(Thostptr, chostFileSize, hostRecord); if (refToBlock(atcBlockref) == DBTC) { jam(); /******************************************************************* // This signal was intended for DBTC as part of the normal transaction // execution. ********************************************************************/ if (Thostptr.p->noOfPackedWordsTc > (25 - LqhKeyConf::SignalLength)) { jam(); sendPackedSignalTc(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if lqhKeyConf = (LqhKeyConf *) &Thostptr.p->packedWordsTc[Thostptr.p->noOfPackedWordsTc]; Thostptr.p->noOfPackedWordsTc += LqhKeyConf::SignalLength; } else { jam(); /******************************************************************* // This signal was intended for DBLQH as part of log execution or // node recovery. ********************************************************************/ if (Thostptr.p->noOfPackedWordsLqh > (25 - LqhKeyConf::SignalLength)) { jam(); sendPackedSignalLqh(signal, Thostptr.p); } else { jam(); updatePackedList(signal, Thostptr.p, Thostptr.i); }//if lqhKeyConf = (LqhKeyConf *) &Thostptr.p->packedWordsLqh[Thostptr.p->noOfPackedWordsLqh]; Thostptr.p->noOfPackedWordsLqh += LqhKeyConf::SignalLength; }//if Uint32 ptrAndType = tcConnectptr.i | (ZLQHKEYCONF << 28); Uint32 tcOprec = tcConnectptr.p->tcOprec; Uint32 ownRef = cownref; Uint32 readlenAi = tcConnectptr.p->readlenAi; Uint32 transid1 = tcConnectptr.p->transid[0]; Uint32 transid2 = tcConnectptr.p->transid[1]; Uint32 noFiredTriggers = tcConnectptr.p->noFiredTriggers; lqhKeyConf->connectPtr = ptrAndType; lqhKeyConf->opPtr = tcOprec; lqhKeyConf->userRef = ownRef; lqhKeyConf->readLen = readlenAi; lqhKeyConf->transId1 = transid1; lqhKeyConf->transId2 = transid2; lqhKeyConf->noFiredTriggers = noFiredTriggers; }//Dblqh::sendLqhkeyconfTc() /* ************************************************************************>> * KEYINFO: Get tuple request from DBTC. Next step is to contact DBACC to get * key to tuple if all key/attrinfo has been received, else for more attrinfo * signals. * ************************************************************************>> */ void Dblqh::execKEYINFO(Signal* signal) { Uint32 tcOprec = signal->theData[0]; Uint32 transid1 = signal->theData[1]; Uint32 transid2 = signal->theData[2]; jamEntry(); if (findTransaction(transid1, transid2, tcOprec) != ZOK) { jam(); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; TcConnectionrec::TransactionState state = regTcPtr->transactionState; if (state != TcConnectionrec::WAIT_TUPKEYINFO && state != TcConnectionrec::WAIT_SCAN_AI) { jam(); /*****************************************************************************/ /* TRANSACTION WAS ABORTED, THIS IS MOST LIKELY A SIGNAL BELONGING TO THE */ /* ABORTED TRANSACTION. THUS IGNORE THE SIGNAL. */ /*****************************************************************************/ return; }//if Uint32 errorCode = handleLongTupKey(signal, (Uint32)regTcPtr->save1, (Uint32)regTcPtr->primKeyLen, &signal->theData[3]); if (errorCode != 0) { if (errorCode == 1) { jam(); return; }//if jam(); abort(); terrorCode = errorCode; abortErrorLab(signal); return; }//if if(state == TcConnectionrec::WAIT_TUPKEYINFO) { FragrecordPtr regFragptr; regFragptr.i = regTcPtr->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); fragptr = regFragptr; endgettupkeyLab(signal); } return; }//Dblqh::execKEYINFO() /* ------------------------------------------------------------------------- */ /* FILL IN KEY DATA INTO DATA BUFFERS. */ /* ------------------------------------------------------------------------- */ Uint32 Dblqh::handleLongTupKey(Signal* signal, Uint32 keyLength, Uint32 primKeyLength, Uint32* dataPtr) { TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 dataPos = 0; while (true) { keyLength += 4; if (cfirstfreeDatabuf == RNIL) { jam(); return ZGET_DATAREC_ERROR; }//if seizeTupkeybuf(signal); Databuf * const regDataPtr = databufptr.p; Uint32 data0 = dataPtr[dataPos]; Uint32 data1 = dataPtr[dataPos + 1]; Uint32 data2 = dataPtr[dataPos + 2]; Uint32 data3 = dataPtr[dataPos + 3]; regDataPtr->data[0] = data0; regDataPtr->data[1] = data1; regDataPtr->data[2] = data2; regDataPtr->data[3] = data3; dataPos += 4; if (keyLength < primKeyLength) { if (dataPos > 16) { jam(); /* SAVE STATE AND WAIT FOR KEYINFO */ regTcPtr->save1 = keyLength; return 1; }//if } else { jam(); return 0; }//if }//while }//Dblqh::handleLongTupKey() /* ------------------------------------------------------------------------- */ /* ------- HANDLE ATTRINFO SIGNALS ------- */ /* */ /* ------------------------------------------------------------------------- */ /* ************************************************************************>> */ /* ATTRINFO: Continuation of KEYINFO signal (except for scans that do not use*/ /* any KEYINFO). When all key and attribute info is received we contact DBACC*/ /* for index handling. */ /* ************************************************************************>> */ void Dblqh::execATTRINFO(Signal* signal) { Uint32 tcOprec = signal->theData[0]; Uint32 transid1 = signal->theData[1]; Uint32 transid2 = signal->theData[2]; jamEntry(); if (findTransaction(transid1, transid2, tcOprec) != ZOK) { jam(); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 length = signal->length() - 3; Uint32 totReclenAi = regTcPtr->totReclenAi; Uint32 currReclenAi = regTcPtr->currReclenAi + length; Uint32* dataPtr = &signal->theData[3]; regTcPtr->currReclenAi = currReclenAi; if (totReclenAi == currReclenAi) { switch (regTcPtr->transactionState) { case TcConnectionrec::WAIT_ATTR: { Fragrecord *regFragrecord = fragrecord; Uint32 fragIndex = regTcPtr->fragmentptr; Uint32 tfragrecFileSize = cfragrecFileSize; jam(); fragptr.i = fragIndex; ptrCheckGuard(fragptr, tfragrecFileSize, regFragrecord); lqhAttrinfoLab(signal, dataPtr, length); endgettupkeyLab(signal); return; break; } case TcConnectionrec::WAIT_SCAN_AI: jam(); scanAttrinfoLab(signal, dataPtr, length); return; break; case TcConnectionrec::WAIT_TUP_TO_ABORT: case TcConnectionrec::LOG_ABORT_QUEUED: case TcConnectionrec::ABORT_QUEUED: case TcConnectionrec::ABORT_STOPPED: case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::WAIT_AI_AFTER_ABORT: jam(); aiStateErrorCheckLab(signal, dataPtr,length); return; break; default: jam(); ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE); break; }//switch } else if (currReclenAi < totReclenAi) { jam(); switch (regTcPtr->transactionState) { case TcConnectionrec::WAIT_ATTR: jam(); lqhAttrinfoLab(signal, dataPtr, length); return; break; case TcConnectionrec::WAIT_SCAN_AI: jam(); scanAttrinfoLab(signal, dataPtr, length); return; break; case TcConnectionrec::WAIT_TUP_TO_ABORT: case TcConnectionrec::LOG_ABORT_QUEUED: case TcConnectionrec::ABORT_QUEUED: case TcConnectionrec::ABORT_STOPPED: case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::WAIT_AI_AFTER_ABORT: jam(); aiStateErrorCheckLab(signal, dataPtr, length); return; break; default: jam(); ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE); break; }//switch } else { switch (regTcPtr->transactionState) { case TcConnectionrec::WAIT_SCAN_AI: jam(); scanAttrinfoLab(signal, dataPtr, length); return; break; default: ndbrequire(false); break; }//switch }//if return; }//Dblqh::execATTRINFO() /* ************************************************************************>> */ /* TUP_ATTRINFO: Interpreted execution in DBTUP generates redo-log info */ /* which is sent back to DBLQH for logging. This is because the decision */ /* to execute or not is made in DBTUP and thus we cannot start logging until */ /* DBTUP part has been run. */ /* ************************************************************************>> */ void Dblqh::execTUP_ATTRINFO(Signal* signal) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 length = signal->length() - 3; Uint32 tcIndex = signal->theData[0]; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; jamEntry(); tcConnectptr.i = tcIndex; ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::WAIT_TUP); if (saveTupattrbuf(signal, &signal->theData[3], length) == ZOK) { return; } else { jam(); /* ------------------------------------------------------------------------- */ /* WE ARE WAITING FOR RESPONSE FROM TUP HERE. THUS WE NEED TO */ /* GO THROUGH THE STATE MACHINE FOR THE OPERATION. */ /* ------------------------------------------------------------------------- */ localAbortStateHandlerLab(signal); }//if }//Dblqh::execTUP_ATTRINFO() /* ------------------------------------------------------------------------- */ /* ------- HANDLE ATTRINFO FROM LQH ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::lqhAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->operation != ZREAD) { if (regTcPtr->opExec != 1) { if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { ; } else { jam(); /* ------------------------------------------------------------------------- */ /* WE MIGHT BE WAITING FOR RESPONSE FROM SOME BLOCK HERE. THUS WE NEED TO */ /* GO THROUGH THE STATE MACHINE FOR THE OPERATION. */ /* ------------------------------------------------------------------------- */ localAbortStateHandlerLab(signal); return; }//if }//if }//if Uint32 sig0 = regTcPtr->tupConnectrec; Uint32 blockNo = refToBlock(regTcPtr->tcTupBlockref); signal->theData[0] = sig0; EXECUTE_DIRECT(blockNo, GSN_ATTRINFO, signal, length + 3); jamEntry(); }//Dblqh::lqhAttrinfoLab() /* ------------------------------------------------------------------------- */ /* ------ FIND TRANSACTION BY USING HASH TABLE ------- */ /* */ /* ------------------------------------------------------------------------- */ int Dblqh::findTransaction(UintR Transid1, UintR Transid2, UintR TcOprec) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; TcConnectionrecPtr locTcConnectptr; Uint32 ThashIndex = (Transid1 ^ TcOprec) & 1023; locTcConnectptr.i = ctransidHash[ThashIndex]; while (locTcConnectptr.i != RNIL) { ptrCheckGuard(locTcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); if ((locTcConnectptr.p->transid[0] == Transid1) && (locTcConnectptr.p->transid[1] == Transid2) && (locTcConnectptr.p->tcOprec == TcOprec)) { /* FIRST PART OF TRANSACTION CORRECT */ /* SECOND PART ALSO CORRECT */ /* THE OPERATION RECORD POINTER IN TC WAS ALSO CORRECT */ jam(); tcConnectptr.i = locTcConnectptr.i; tcConnectptr.p = locTcConnectptr.p; return (int)ZOK; }//if jam(); /* THIS WAS NOT THE TRANSACTION WHICH WAS SOUGHT */ locTcConnectptr.i = locTcConnectptr.p->nextHashRec; }//while /* WE DID NOT FIND THE TRANSACTION, REPORT NOT FOUND */ return (int)ZNOT_FOUND; }//Dblqh::findTransaction() /* ------------------------------------------------------------------------- */ /* ------- SAVE ATTRINFO FROM TUP IN ATTRINBUF ------- */ /* */ /* ------------------------------------------------------------------------- */ int Dblqh::saveTupattrbuf(Signal* signal, Uint32* dataPtr, Uint32 length) { Uint32 tfirstfreeAttrinbuf = cfirstfreeAttrinbuf; TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 currTupAiLen = regTcPtr->currTupAiLen; if (tfirstfreeAttrinbuf == RNIL) { jam(); terrorCode = ZGET_ATTRINBUF_ERROR; return ZGET_ATTRINBUF_ERROR; }//if seizeAttrinbuf(signal); Attrbuf * const regAttrPtr = attrinbufptr.p; MEMCOPY_NO_WORDS(®AttrPtr->attrbuf[0], dataPtr, length); regTcPtr->currTupAiLen = currTupAiLen + length; regAttrPtr->attrbuf[ZINBUF_DATA_LEN] = length; return ZOK; }//Dblqh::saveTupattrbuf() /* ========================================================================== * ======= SEIZE ATTRIBUTE IN BUFFER ======= * * GET A NEW ATTRINBUF AND SETS ATTRINBUFPTR. * ========================================================================= */ void Dblqh::seizeAttrinbuf(Signal* signal) { AttrbufPtr tmpAttrinbufptr; AttrbufPtr regAttrinbufptr; Attrbuf *regAttrbuf = attrbuf; Uint32 tattrinbufFileSize = cattrinbufFileSize; regAttrinbufptr.i = seize_attrinbuf(); tmpAttrinbufptr.i = tcConnectptr.p->lastAttrinbuf; ptrCheckGuard(regAttrinbufptr, tattrinbufFileSize, regAttrbuf); tcConnectptr.p->lastAttrinbuf = regAttrinbufptr.i; regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN] = 0; if (tmpAttrinbufptr.i == RNIL) { jam(); tcConnectptr.p->firstAttrinbuf = regAttrinbufptr.i; } else { jam(); ptrCheckGuard(tmpAttrinbufptr, tattrinbufFileSize, regAttrbuf); tmpAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = regAttrinbufptr.i; }//if regAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL; attrinbufptr = regAttrinbufptr; }//Dblqh::seizeAttrinbuf() /* ========================================================================== * ======= SEIZE TC CONNECT RECORD ======= * * GETS A NEW TC CONNECT RECORD FROM FREELIST. * ========================================================================= */ void Dblqh::seizeTcrec() { TcConnectionrecPtr locTcConnectptr; locTcConnectptr.i = cfirstfreeTcConrec; ptrCheckGuard(locTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); Uint32 nextTc = locTcConnectptr.p->nextTcConnectrec; locTcConnectptr.p->nextTcConnectrec = RNIL; locTcConnectptr.p->clientConnectrec = RNIL; locTcConnectptr.p->clientBlockref = RNIL; locTcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; locTcConnectptr.p->tcTimer = cLqhTimeOutCount; locTcConnectptr.p->tableref = RNIL; locTcConnectptr.p->savePointId = 0; cfirstfreeTcConrec = nextTc; tcConnectptr = locTcConnectptr; locTcConnectptr.p->connectState = TcConnectionrec::CONNECTED; }//Dblqh::seizeTcrec() /* ========================================================================== * ======= SEIZE DATA BUFFER ======= * ========================================================================= */ void Dblqh::seizeTupkeybuf(Signal* signal) { Databuf *regDatabuf = databuf; DatabufPtr tmpDatabufptr; DatabufPtr regDatabufptr; Uint32 tdatabufFileSize = cdatabufFileSize; /* ------- GET A DATABUF. ------- */ regDatabufptr.i = cfirstfreeDatabuf; tmpDatabufptr.i = tcConnectptr.p->lastTupkeybuf; ptrCheckGuard(regDatabufptr, tdatabufFileSize, regDatabuf); Uint32 nextFirst = regDatabufptr.p->nextDatabuf; tcConnectptr.p->lastTupkeybuf = regDatabufptr.i; if (tmpDatabufptr.i == RNIL) { jam(); tcConnectptr.p->firstTupkeybuf = regDatabufptr.i; } else { jam(); ptrCheckGuard(tmpDatabufptr, tdatabufFileSize, regDatabuf); tmpDatabufptr.p->nextDatabuf = regDatabufptr.i; }//if cfirstfreeDatabuf = nextFirst; regDatabufptr.p->nextDatabuf = RNIL; databufptr = regDatabufptr; }//Dblqh::seizeTupkeybuf() /* ------------------------------------------------------------------------- */ /* ------- TAKE CARE OF LQHKEYREQ ------- */ /* LQHKEYREQ IS THE SIGNAL THAT STARTS ALL OPERATIONS IN THE LQH BLOCK */ /* THIS SIGNAL CONTAINS A LOT OF INFORMATION ABOUT WHAT TYPE OF OPERATION, */ /* KEY INFORMATION, ATTRIBUTE INFORMATION, NODE INFORMATION AND A LOT MORE */ /* ------------------------------------------------------------------------- */ void Dblqh::execLQHKEYREQ(Signal* signal) { UintR sig0, sig1, sig2, sig3, sig4, sig5; Uint8 tfragDistKey; const LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)signal->getDataPtr(); sig0 = lqhKeyReq->clientConnectPtr; if (cfirstfreeTcConrec != RNIL && !ERROR_INSERTED(5031)) { jamEntry(); seizeTcrec(); } else { /* ------------------------------------------------------------------------- */ /* NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST. */ /* ------------------------------------------------------------------------- */ if (ERROR_INSERTED(5031)) { CLEAR_ERROR_INSERT_VALUE; } noFreeRecordLab(signal, lqhKeyReq, ZNO_TC_CONNECT_ERROR); return; }//if if(ERROR_INSERTED(5038) && refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ jam(); SET_ERROR_INSERT_VALUE(5039); return; } c_Counters.operations++; TcConnectionrec * const regTcPtr = tcConnectptr.p; regTcPtr->clientBlockref = signal->senderBlockRef(); regTcPtr->clientConnectrec = sig0; regTcPtr->tcOprec = sig0; regTcPtr->storedProcId = ZNIL; UintR TtotReclenAi = lqhKeyReq->attrLen; sig1 = lqhKeyReq->savePointId; sig2 = lqhKeyReq->hashValue; UintR Treqinfo = lqhKeyReq->requestInfo; sig4 = lqhKeyReq->tableSchemaVersion; sig5 = lqhKeyReq->tcBlockref; regTcPtr->savePointId = sig1; regTcPtr->hashValue = sig2; const Uint32 schemaVersion = regTcPtr->schemaVersion = LqhKeyReq::getSchemaVersion(sig4); tabptr.i = LqhKeyReq::getTableId(sig4); regTcPtr->tcBlockref = sig5; const Uint8 op = LqhKeyReq::getOperation(Treqinfo); if (op == ZREAD && !getAllowRead()){ noFreeRecordLab(signal, lqhKeyReq, ZNODE_SHUTDOWN_IN_PROGESS); return; } regTcPtr->totReclenAi = LqhKeyReq::getAttrLen(TtotReclenAi); regTcPtr->tcScanInfo = lqhKeyReq->scanInfo; regTcPtr->indTakeOver = LqhKeyReq::getScanTakeOverFlag(TtotReclenAi); regTcPtr->readlenAi = 0; regTcPtr->currTupAiLen = 0; regTcPtr->listState = TcConnectionrec::NOT_IN_LIST; regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; regTcPtr->fragmentptr = RNIL; sig0 = lqhKeyReq->fragmentData; sig1 = lqhKeyReq->transId1; sig2 = lqhKeyReq->transId2; sig3 = lqhKeyReq->variableData[0]; sig4 = lqhKeyReq->variableData[1]; regTcPtr->fragmentid = LqhKeyReq::getFragmentId(sig0); regTcPtr->nextReplica = LqhKeyReq::getNextReplicaNodeId(sig0); regTcPtr->transid[0] = sig1; regTcPtr->transid[1] = sig2; regTcPtr->applRef = sig3; regTcPtr->applOprec = sig4; regTcPtr->commitAckMarker = RNIL; if(LqhKeyReq::getMarkerFlag(Treqinfo)){ jam(); CommitAckMarkerPtr markerPtr; m_commitAckMarkerHash.seize(markerPtr); if(markerPtr.i == RNIL){ noFreeRecordLab(signal, lqhKeyReq, ZNO_FREE_MARKER_RECORDS_ERROR); return; } markerPtr.p->transid1 = sig1; markerPtr.p->transid2 = sig2; markerPtr.p->apiRef = sig3; markerPtr.p->apiOprec = sig4; const NodeId tcNodeId = refToNode(sig5); markerPtr.p->tcNodeId = tcNodeId; CommitAckMarkerPtr tmp; #ifdef VM_TRACE #ifdef MARKER_TRACE ndbout_c("Add marker[%.8x %.8x]", markerPtr.p->transid1, markerPtr.p->transid2); #endif ndbrequire(!m_commitAckMarkerHash.find(tmp, * markerPtr.p)); #endif m_commitAckMarkerHash.add(markerPtr); regTcPtr->commitAckMarker = markerPtr.i; } regTcPtr->reqinfo = Treqinfo; regTcPtr->lastReplicaNo = LqhKeyReq::getLastReplicaNo(Treqinfo); regTcPtr->lockType = LqhKeyReq::getLockType(Treqinfo); regTcPtr->dirtyOp = LqhKeyReq::getDirtyFlag(Treqinfo); regTcPtr->opExec = LqhKeyReq::getInterpretedFlag(Treqinfo); regTcPtr->opSimple = LqhKeyReq::getSimpleFlag(Treqinfo); regTcPtr->simpleRead = ((Treqinfo >> 18) & 15); regTcPtr->operation = LqhKeyReq::getOperation(Treqinfo); regTcPtr->seqNoReplica = LqhKeyReq::getSeqNoReplica(Treqinfo); UintR TreclenAiLqhkey = LqhKeyReq::getAIInLqhKeyReq(Treqinfo); regTcPtr->apiVersionNo = 0; regTcPtr->reclenAiLqhkey = TreclenAiLqhkey; regTcPtr->currReclenAi = TreclenAiLqhkey; UintR TitcKeyLen = LqhKeyReq::getKeyLen(Treqinfo); regTcPtr->primKeyLen = TitcKeyLen; regTcPtr->noFiredTriggers = lqhKeyReq->noFiredTriggers; UintR TapplAddressInd = LqhKeyReq::getApplicationAddressFlag(Treqinfo); UintR nextPos = (TapplAddressInd << 1); UintR TsameClientAndTcOprec = LqhKeyReq::getSameClientAndTcFlag(Treqinfo); if (TsameClientAndTcOprec == 1) { regTcPtr->tcOprec = lqhKeyReq->variableData[nextPos]; nextPos++; }//if UintR TnextReplicasIndicator = regTcPtr->lastReplicaNo - regTcPtr->seqNoReplica; if (TnextReplicasIndicator > 1) { regTcPtr->nodeAfterNext[0] = lqhKeyReq->variableData[nextPos] & 0xFFFF; regTcPtr->nodeAfterNext[1] = lqhKeyReq->variableData[nextPos] >> 16; nextPos++; }//if UintR TstoredProcIndicator = LqhKeyReq::getStoredProcFlag(TtotReclenAi); if (TstoredProcIndicator == 1) { regTcPtr->storedProcId = lqhKeyReq->variableData[nextPos] & ZNIL; nextPos++; }//if UintR TreadLenAiIndicator = LqhKeyReq::getReturnedReadLenAIFlag(Treqinfo); if (TreadLenAiIndicator == 1) { regTcPtr->readlenAi = lqhKeyReq->variableData[nextPos] & ZNIL; nextPos++; }//if sig0 = lqhKeyReq->variableData[nextPos + 0]; sig1 = lqhKeyReq->variableData[nextPos + 1]; sig2 = lqhKeyReq->variableData[nextPos + 2]; sig3 = lqhKeyReq->variableData[nextPos + 3]; regTcPtr->tupkeyData[0] = sig0; regTcPtr->tupkeyData[1] = sig1; regTcPtr->tupkeyData[2] = sig2; regTcPtr->tupkeyData[3] = sig3; if (TitcKeyLen > 0) { if (TitcKeyLen < 4) { nextPos += TitcKeyLen; } else { nextPos += 4; }//if } else { LQHKEY_error(signal, 3); return; }//if if ((LqhKeyReq::FixedSignalLength + nextPos + TreclenAiLqhkey) != signal->length()) { LQHKEY_error(signal, 2); return; }//if UintR TseqNoReplica = regTcPtr->seqNoReplica; UintR TlastReplicaNo = regTcPtr->lastReplicaNo; if (TseqNoReplica == TlastReplicaNo) { jam(); regTcPtr->nextReplica = ZNIL; } else { if (TseqNoReplica < TlastReplicaNo) { jam(); regTcPtr->nextSeqNoReplica = TseqNoReplica + 1; if ((regTcPtr->nextReplica == 0) || (regTcPtr->nextReplica == cownNodeid)) { LQHKEY_error(signal, 0); }//if } else { LQHKEY_error(signal, 4); return; }//if }//if TcConnectionrecPtr localNextTcConnectptr; Uint32 hashIndex = (regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023; localNextTcConnectptr.i = ctransidHash[hashIndex]; ctransidHash[hashIndex] = tcConnectptr.i; regTcPtr->prevHashRec = RNIL; regTcPtr->nextHashRec = localNextTcConnectptr.i; if (localNextTcConnectptr.i != RNIL) { /* -------------------------------------------------------------------------- */ /* ENSURE THAT THE NEXT RECORD HAS SET PREVIOUS TO OUR RECORD IF IT EXISTS */ /* -------------------------------------------------------------------------- */ ptrCheckGuard(localNextTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); jam(); localNextTcConnectptr.p->prevHashRec = tcConnectptr.i; }//if if (tabptr.i >= ctabrecFileSize) { LQHKEY_error(signal, 5); return; }//if ptrAss(tabptr, tablerec); if(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED){ LQHKEY_abort(signal, 4); return; } if(tabptr.p->schemaVersion != schemaVersion){ LQHKEY_abort(signal, 5); return; } regTcPtr->tableref = tabptr.i; tabptr.p->usageCount++; if (!getFragmentrec(signal, regTcPtr->fragmentid)) { LQHKEY_error(signal, 6); return; }//if regTcPtr->localFragptr = (regTcPtr->hashValue >> fragptr.p->hashCheckBit) & 1; Uint8 TcopyType = fragptr.p->fragCopy; tfragDistKey = fragptr.p->fragDistributionKey; if (fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION) { jam(); regTcPtr->activeCreat = ZTRUE; CRASH_INSERTION(5002); } else { regTcPtr->activeCreat = ZFALSE; }//if regTcPtr->replicaType = TcopyType; regTcPtr->fragmentptr = fragptr.i; Uint8 TdistKey = LqhKeyReq::getDistributionKey(TtotReclenAi); if ((tfragDistKey != TdistKey) && (regTcPtr->seqNoReplica == 0) && (regTcPtr->dirtyOp == ZFALSE) && (regTcPtr->simpleRead != ZSIMPLE_READ)) { /* ---------------------------------------------------------------------- * WE HAVE DIFFERENT OPINION THAN THE DIH THAT STARTED THE TRANSACTION. * THE REASON COULD BE THAT THIS IS AN OLD DISTRIBUTION WHICH IS NO LONGER * VALID TO USE. THIS MUST BE CHECKED. * ONE IS ADDED TO THE DISTRIBUTION KEY EVERY TIME WE ADD A NEW REPLICA. * FAILED REPLICAS DO NOT AFFECT THE DISTRIBUTION KEY. THIS MEANS THAT THE * MAXIMUM DEVIATION CAN BE ONE BETWEEN THOSE TWO VALUES. * ---------------------------------------------------------------------- */ Int32 tmp = TdistKey - tfragDistKey; tmp = (tmp < 0 ? - tmp : tmp); if ((tmp <= 1) || (tfragDistKey == 0)) { LQHKEY_abort(signal, 0); return; }//if LQHKEY_error(signal, 1); }//if if (TreclenAiLqhkey != 0) { if (regTcPtr->operation != ZREAD) { if (regTcPtr->operation != ZDELETE) { if (regTcPtr->opExec != 1) { jam(); /*---------------------------------------------------------------------------*/ /* */ /* UPDATES, WRITES AND INSERTS THAT ARE NOT INTERPRETED WILL USE THE */ /* SAME ATTRINFO IN ALL REPLICAS. THUS WE SAVE THE ATTRINFO ALREADY */ /* TO SAVE A SIGNAL FROM TUP TO LQH. INTERPRETED EXECUTION IN TUP */ /* WILL CREATE NEW ATTRINFO FOR THE OTHER REPLICAS AND IT IS THUS NOT */ /* A GOOD IDEA TO SAVE THE INFORMATION HERE. READS WILL ALSO BE */ /* UNNECESSARY TO SAVE SINCE THAT ATTRINFO WILL NEVER BE SENT TO ANY */ /* MORE REPLICAS. */ /*---------------------------------------------------------------------------*/ /* READS AND DELETES CAN ONLY HAVE INFORMATION ABOUT WHAT IS TO BE READ. */ /* NO INFORMATION THAT NEEDS LOGGING. */ /*---------------------------------------------------------------------------*/ sig0 = lqhKeyReq->variableData[nextPos + 0]; sig1 = lqhKeyReq->variableData[nextPos + 1]; sig2 = lqhKeyReq->variableData[nextPos + 2]; sig3 = lqhKeyReq->variableData[nextPos + 3]; sig4 = lqhKeyReq->variableData[nextPos + 4]; regTcPtr->firstAttrinfo[0] = sig0; regTcPtr->firstAttrinfo[1] = sig1; regTcPtr->firstAttrinfo[2] = sig2; regTcPtr->firstAttrinfo[3] = sig3; regTcPtr->firstAttrinfo[4] = sig4; regTcPtr->currTupAiLen = TreclenAiLqhkey; } else { jam(); regTcPtr->reclenAiLqhkey = 0; }//if } else { jam(); regTcPtr->reclenAiLqhkey = 0; }//if }//if sig0 = lqhKeyReq->variableData[nextPos + 0]; sig1 = lqhKeyReq->variableData[nextPos + 1]; sig2 = lqhKeyReq->variableData[nextPos + 2]; sig3 = lqhKeyReq->variableData[nextPos + 3]; sig4 = lqhKeyReq->variableData[nextPos + 4]; signal->theData[0] = regTcPtr->tupConnectrec; signal->theData[3] = sig0; signal->theData[4] = sig1; signal->theData[5] = sig2; signal->theData[6] = sig3; signal->theData[7] = sig4; EXECUTE_DIRECT(refToBlock(regTcPtr->tcTupBlockref), GSN_ATTRINFO, signal, TreclenAiLqhkey + 3); jamEntry(); if (signal->theData[0] == (UintR)-1) { LQHKEY_abort(signal, 2); return; }//if }//if /* ------- TAKE CARE OF PRIM KEY DATA ------- */ if (regTcPtr->primKeyLen <= 4) { endgettupkeyLab(signal); return; } else { jam(); /*--------------------------------------------------------------------*/ /* KEY LENGTH WAS MORE THAN 4 WORDS (WORD = 4 BYTE). THUS WE */ /* HAVE TO ALLOCATE A DATA BUFFER TO STORE THE KEY DATA AND */ /* WAIT FOR THE KEYINFO SIGNAL. */ /*--------------------------------------------------------------------*/ regTcPtr->save1 = 4; regTcPtr->transactionState = TcConnectionrec::WAIT_TUPKEYINFO; return; }//if return; }//Dblqh::execLQHKEYREQ() void Dblqh::endgettupkeyLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->totReclenAi == regTcPtr->currReclenAi) { ; } else { jam(); ndbrequire(regTcPtr->currReclenAi < regTcPtr->totReclenAi); regTcPtr->transactionState = TcConnectionrec::WAIT_ATTR; return; }//if /* ---------------------------------------------------------------------- */ /* NOW RECEPTION OF LQHKEYREQ IS COMPLETED THE NEXT STEP IS TO START*/ /* PROCESSING THE MESSAGE. IF THE MESSAGE IS TO A STAND-BY NODE */ /* WITHOUT NETWORK REDUNDANCY OR PREPARE-TO-COMMIT ACTIVATED THE */ /* PREPARATION TO SEND TO THE NEXT NODE WILL START IMMEDIATELY. */ /* */ /* OTHERWISE THE PROCESSING WILL START AFTER SETTING THE PROPER */ /* STATE. HOWEVER BEFORE PROCESSING THE MESSAGE */ /* IT IS NECESSARY TO CHECK THAT THE FRAGMENT IS NOT PERFORMING */ /* A CHECKPOINT. THE OPERATION SHALL ALSO BE LINKED INTO THE */ /* FRAGMENT QUEUE OR LIST OF ACTIVE OPERATIONS. */ /* */ /* THE FIRST STEP IN PROCESSING THE MESSAGE IS TO CONTACT DBACC. */ /*------------------------------------------------------------------------*/ switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: case Fragrecord::CRASH_RECOVERING: case Fragrecord::ACTIVE_CREATION: linkActiveFrag(signal); prepareContinueAfterBlockedLab(signal); return; break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); regTcPtr->transactionState = TcConnectionrec::STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); break; }//switch return; }//Dblqh::endgettupkeyLab() void Dblqh::prepareContinueAfterBlockedLab(Signal* signal) { UintR ttcScanOp; UintR taccreq; /* -------------------------------------------------------------------------- */ /* INPUT: TC_CONNECTPTR ACTIVE CONNECTION RECORD */ /* FRAGPTR FRAGMENT RECORD */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT. */ /* -------------------------------------------------------------------------- */ /* ALSO AFTER NORMAL PROCEDURE WE CONTINUE HERE */ /* -------------------------------------------------------------------------- */ Uint32 tc_ptr_i = tcConnectptr.i; TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->indTakeOver == ZTRUE) { jam(); ttcScanOp = KeyInfo20::getScanOp(regTcPtr->tcScanInfo); scanptr.i = RNIL; { ScanRecord key; key.scanNumber = KeyInfo20::getScanNo(regTcPtr->tcScanInfo); key.fragPtrI = fragptr.i; c_scanTakeOverHash.find(scanptr, key); #ifdef TRACE_SCAN_TAKEOVER if(scanptr.i == RNIL) ndbout_c("not finding (%d %d)", key.scanNumber, key.fragPtrI); #endif } if (scanptr.i == RNIL) { jam(); releaseActiveFrag(signal); takeOverErrorLab(signal); return; }//if Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, ttcScanOp, true); if (accOpPtr == RNIL) { jam(); releaseActiveFrag(signal); takeOverErrorLab(signal); return; }//if signal->theData[1] = accOpPtr; signal->theData[2] = regTcPtr->transid[0]; signal->theData[3] = regTcPtr->transid[1]; EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACC_TO_REQ, signal, 4); if (signal->theData[0] == (UintR)-1) { execACC_TO_REF(signal); return; }//if jamEntry(); }//if /*-------------------------------------------------------------------*/ /* IT IS NOW TIME TO CONTACT ACC. THE TUPLE KEY WILL BE SENT */ /* AND THIS WILL BE TRANSLATED INTO A LOCAL KEY BY USING THE */ /* LOCAL PART OF THE LH3-ALGORITHM. ALSO PROPER LOCKS ON THE */ /* TUPLE WILL BE SET. FOR INSERTS AND DELETES THE MESSAGE WILL */ /* START AN INSERT/DELETE INTO THE HASH TABLE. */ /* */ /* BEFORE SENDING THE MESSAGE THE REQUEST INFORMATION IS SET */ /* PROPERLY. */ /* ----------------------------------------------------------------- */ #if 0 if (regTcPtr->tableref != 0) { switch (regTcPtr->operation) { case ZREAD: ndbout << "Läsning "; break; case ZUPDATE: ndbout << " Uppdatering "; break; case ZWRITE: ndbout << "Write "; break; case ZINSERT: ndbout << "Inläggning "; break; case ZDELETE: ndbout << "Borttagning "; break; default: ndbout << "????"; break; } ndbout << "med nyckel = " << regTcPtr->tupkeyData[0] << endl; } #endif regTcPtr->transactionState = TcConnectionrec::WAIT_ACC; taccreq = regTcPtr->operation; taccreq = taccreq + (regTcPtr->opSimple << 3); taccreq = taccreq + (regTcPtr->lockType << 4); taccreq = taccreq + (regTcPtr->dirtyOp << 6); taccreq = taccreq + (regTcPtr->replicaType << 7); taccreq = taccreq + (regTcPtr->apiVersionNo << 9); /* ************ */ /* ACCKEYREQ < */ /* ************ */ ndbrequire(regTcPtr->localFragptr < 2); Uint32 sig0, sig1, sig2, sig3, sig4; sig0 = regTcPtr->accConnectrec; sig1 = fragptr.p->accFragptr[regTcPtr->localFragptr]; sig2 = regTcPtr->hashValue; sig3 = regTcPtr->primKeyLen; sig4 = regTcPtr->transid[0]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->theData[2] = taccreq; signal->theData[3] = sig2; signal->theData[4] = sig3; signal->theData[5] = sig4; sig0 = regTcPtr->transid[1]; sig1 = regTcPtr->tupkeyData[0]; sig2 = regTcPtr->tupkeyData[1]; sig3 = regTcPtr->tupkeyData[2]; sig4 = regTcPtr->tupkeyData[3]; signal->theData[6] = sig0; signal->theData[7] = sig1; signal->theData[8] = sig2; signal->theData[9] = sig3; signal->theData[10] = sig4; if (regTcPtr->primKeyLen > 4) { sendKeyinfoAcc(signal, 11); }//if EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACCKEYREQ, signal, 7 + regTcPtr->primKeyLen); if (signal->theData[0] < RNIL) { signal->theData[0] = tc_ptr_i; execACCKEYCONF(signal); return; } else if (signal->theData[0] == RNIL) { ; } else { ndbrequire(signal->theData[0] == (UintR)-1); signal->theData[0] = tc_ptr_i; execACCKEYREF(signal); }//if return; }//Dblqh::prepareContinueAfterBlockedLab() /* ========================================================================== */ /* ======= SEND KEYINFO TO ACC ======= */ /* */ /* ========================================================================== */ void Dblqh::sendKeyinfoAcc(Signal* signal, Uint32 Ti) { DatabufPtr regDatabufptr; regDatabufptr.i = tcConnectptr.p->firstTupkeybuf; do { jam(); ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); Uint32 sig0 = regDatabufptr.p->data[0]; Uint32 sig1 = regDatabufptr.p->data[1]; Uint32 sig2 = regDatabufptr.p->data[2]; Uint32 sig3 = regDatabufptr.p->data[3]; signal->theData[Ti] = sig0; signal->theData[Ti + 1] = sig1; signal->theData[Ti + 2] = sig2; signal->theData[Ti + 3] = sig3; regDatabufptr.i = regDatabufptr.p->nextDatabuf; Ti += 4; } while (regDatabufptr.i != RNIL); }//Dblqh::sendKeyinfoAcc() void Dblqh::execLQH_ALLOCREQ(Signal* signal) { TcConnectionrecPtr regTcPtr; FragrecordPtr regFragptr; jamEntry(); regTcPtr.i = signal->theData[0]; ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec); regFragptr.i = regTcPtr.p->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); ndbrequire(regTcPtr.p->localFragptr < 2); signal->theData[0] = regTcPtr.p->tupConnectrec; signal->theData[1] = regFragptr.p->tupFragptr[regTcPtr.p->localFragptr]; signal->theData[2] = regTcPtr.p->tableref; Uint32 tup = refToBlock(regTcPtr.p->tcTupBlockref); EXECUTE_DIRECT(tup, GSN_TUP_ALLOCREQ, signal, 3); }//Dblqh::execTUP_ALLOCREQ() /* ************>> */ /* ACCKEYCONF > */ /* ************>> */ void Dblqh::execACCKEYCONF(Signal* signal) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; Uint32 tcIndex = signal->theData[0]; Uint32 Tfragid = signal->theData[2]; Uint32 localKey1 = signal->theData[3]; Uint32 localKey2 = signal->theData[4]; Uint32 localKeyFlag = signal->theData[5]; jamEntry(); tcConnectptr.i = tcIndex; ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->transactionState != TcConnectionrec::WAIT_ACC) { LQHKEY_abort(signal, 3); return; }//if /* ------------------------------------------------------------------------ * Set transaction state and also reset the activeCreat since that is only * valid in cases where the record was not present. * ------------------------------------------------------------------------ */ regTcPtr->transactionState = TcConnectionrec::WAIT_TUP; regTcPtr->activeCreat = ZFALSE; /* ------------------------------------------------------------------------ * IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE * INFORMATION ON WHICH TABLE AND FRAGMENT, THE LOCAL KEY AND IT NEEDS TO * KNOW THE TYPE OF OPERATION TO PERFORM. TUP CAN SEND THE ATTRINFO DATA * EITHER TO THE TC BLOCK OR DIRECTLY TO THE APPLICATION. THE SCHEMA VERSION * IS NEEDED SINCE TWO SCHEMA VERSIONS CAN BE ACTIVE SIMULTANEOUSLY ON A * TABLE. * ------------------------------------------------------------------------ */ if (regTcPtr->operation == ZWRITE) { if (signal->theData[1] > 0) { /* -------------------------------------------------------------------- * ACC did perform an insert and thus we should indicate that the WRITE * is an INSERT otherwise it is an UPDATE. * -------------------------------------------------------------------- */ jam(); regTcPtr->operation = ZINSERT; } else { jam(); tcConnectptr.p->operation = ZUPDATE; }//if }//if ndbrequire(localKeyFlag == 1); localKey2 = localKey1 & MAX_TUPLES_PER_PAGE; localKey1 = localKey1 >> MAX_TUPLES_BITS; Uint32 Ttupreq = regTcPtr->dirtyOp; Ttupreq = Ttupreq + (regTcPtr->opSimple << 1); Ttupreq = Ttupreq + (regTcPtr->operation << 6); Ttupreq = Ttupreq + (regTcPtr->opExec << 10); Ttupreq = Ttupreq + (regTcPtr->apiVersionNo << 11); /* --------------------------------------------------------------------- * Clear interpreted mode bit since we do not want the next replica to * use interpreted mode. The next replica will receive a normal write. * --------------------------------------------------------------------- */ regTcPtr->opExec = 0; /* ************< */ /* TUPKEYREQ < */ /* ************< */ TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); Uint32 sig0, sig1, sig2, sig3; sig0 = regTcPtr->tupConnectrec; sig1 = regTcPtr->tableref; tupKeyReq->connectPtr = sig0; tupKeyReq->request = Ttupreq; tupKeyReq->tableRef = sig1; tupKeyReq->fragId = Tfragid; tupKeyReq->keyRef1 = localKey1; tupKeyReq->keyRef2 = localKey2; sig0 = regTcPtr->totReclenAi; sig1 = regTcPtr->applOprec; sig2 = regTcPtr->applRef; sig3 = regTcPtr->schemaVersion; FragrecordPtr regFragptr; regFragptr.i = regTcPtr->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); tupKeyReq->attrBufLen = sig0; tupKeyReq->opRef = sig1; tupKeyReq->applRef = sig2; tupKeyReq->schemaVersion = sig3; ndbrequire(regTcPtr->localFragptr < 2); sig0 = regTcPtr->storedProcId; sig1 = regTcPtr->transid[0]; sig2 = regTcPtr->transid[1]; sig3 = regFragptr.p->tupFragptr[regTcPtr->localFragptr]; Uint32 tup = refToBlock(regTcPtr->tcTupBlockref); tupKeyReq->storedProcedure = sig0; tupKeyReq->transId1 = sig1; tupKeyReq->transId2 = sig2; tupKeyReq->fragPtr = sig3; tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; tupKeyReq->savePointId = tcConnectptr.p->savePointId; EXECUTE_DIRECT(tup, GSN_TUPKEYREQ, signal, TupKeyReq::SignalLength); }//Dblqh::execACCKEYCONF() /* -------------------------------------------------------------------------- * ------- ENTER TUP... ------- * ENTER TUPKEYCONF WITH * TC_CONNECTPTR, * TDATA2, LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT * TDATA3, LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT * TDATA4, TOTAL LENGTH OF READ DATA SENT TO TC/APPLICATION * TDATA5 TOTAL LENGTH OF UPDATE DATA SENT TO/FROM TUP * GOTO TUPKEY_CONF * * TAKE CARE OF RESPONSES FROM TUPLE MANAGER. * -------------------------------------------------------------------------- */ void Dblqh::tupkeyConfLab(Signal* signal) { /* ---- GET OPERATION TYPE AND CHECK WHAT KIND OF OPERATION IS REQUESTED ---- */ const TupKeyConf * const tupKeyConf = (TupKeyConf *)&signal->theData[0]; TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->simpleRead == ZSIMPLE_READ) { jam(); /* ---------------------------------------------------------------------- * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE OPERATION. * SINCE WE HAVE NOT RELEASED THE FRAGMENT LOCK (FOR LOCAL CHECKPOINTS) YET * WE CAN GO IMMEDIATELY TO COMMIT_CONTINUE_AFTER_BLOCKED. * WE HAVE ALREADY SENT THE RESPONSE SO WE ARE NOT INTERESTED IN READ LENGTH * ---------------------------------------------------------------------- */ regTcPtr->gci = cnewestGci; releaseActiveFrag(signal); commitContinueAfterBlockedLab(signal); return; }//if if (tupKeyConf->readLength != 0) { jam(); /* SET BIT 15 IN REQINFO */ LqhKeyReq::setApplicationAddressFlag(regTcPtr->reqinfo, 1); regTcPtr->readlenAi = tupKeyConf->readLength; }//if regTcPtr->totSendlenAi = tupKeyConf->writeLength; ndbrequire(regTcPtr->totSendlenAi == regTcPtr->currTupAiLen); rwConcludedLab(signal); return; }//Dblqh::tupkeyConfLab() /* -------------------------------------------------------------------------- * THE CODE IS FOUND IN THE SIGNAL RECEPTION PART OF LQH * -------------------------------------------------------------------------- */ void Dblqh::rwConcludedLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; /* ------------------------------------------------------------------------ * WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION. * IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND * FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION. * ------------------------------------------------------------------------ */ if (regTcPtr->operation == ZREAD) { jam(); /* ---------------------------------------------------------------------- * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL THE * COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE. * ---------------------------------------------------------------------- */ releaseActiveFrag(signal); packLqhkeyreqLab(signal); return; } else { FragrecordPtr regFragptr; regFragptr.i = regTcPtr->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); if (regFragptr.p->logFlag == Fragrecord::STATE_FALSE){ if (regTcPtr->dirtyOp == ZTRUE) { jam(); /* ------------------------------------------------------------------ * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND * THAT CAN CAN BE COMMITTED IMMEDIATELY. * ------------------------------------------------------------------ */ regTcPtr->gci = cnewestGci; releaseActiveFrag(signal); commitContinueAfterBlockedLab(signal); return; } else { jam(); /* ------------------------------------------------------------------ * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING. * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC. * ------------------------------------------------------------------ */ regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN; releaseActiveFrag(signal); packLqhkeyreqLab(signal); return; }//if } else { jam(); /* -------------------------------------------------------------------- * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST. * -------------------------------------------------------------------- * A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE * PREMATURELY COMMITTED. * -------------------------------------------------------------------- */ releaseActiveFrag(signal); logLqhkeyreqLab(signal); return; }//if }//if }//Dblqh::rwConcludedLab() void Dblqh::rwConcludedAiLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; fragptr.i = regTcPtr->fragmentptr; /* ------------------------------------------------------------------------ * WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION. * IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND * FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION. * IN THIS CASE WE HAVE ALREADY RELEASED THE FRAGMENT LOCK. * ERROR CASES AT FRAGMENT CREATION AND STAND-BY NODES ARE THE REASONS FOR * COMING HERE. * ------------------------------------------------------------------------ */ if (regTcPtr->operation == ZREAD) { if (regTcPtr->opSimple == 1) { jam(); /* -------------------------------------------------------------------- * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE * OPERATION. * -------------------------------------------------------------------- */ regTcPtr->gci = cnewestGci; localCommitLab(signal); return; } else { jam(); /* -------------------------------------------------------------------- * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL * THE COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE. * -------------------------------------------------------------------- */ ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); packLqhkeyreqLab(signal); return; }//if } else { jam(); ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (fragptr.p->logFlag == Fragrecord::STATE_FALSE) { if (regTcPtr->dirtyOp == ZTRUE) { /* ------------------------------------------------------------------ * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND * THAT CAN CAN BE COMMITTED IMMEDIATELY. * ------------------------------------------------------------------ */ jam(); /* ---------------------------------------------------------------- * IT MUST BE ACTIVE CREATION OF A FRAGMENT. * ---------------------------------------------------------------- */ regTcPtr->gci = cnewestGci; localCommitLab(signal); return; } else { /* ------------------------------------------------------------------ * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING. * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC. * ------------------------------------------------------------------ */ jam(); /* --------------------------------------------------------------- * IT MUST BE ACTIVE CREATION OF A FRAGMENT. * NOT A DIRTY OPERATION THUS PACK REQUEST/RESPONSE. * ---------------------------------------------------------------- */ regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN; packLqhkeyreqLab(signal); return; }//if } else { jam(); /* -------------------------------------------------------------------- * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST. * -------------------------------------------------------------------- */ /* A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE * PREMATURELY COMMITTED. * -------------------------------------------------------------------- */ logLqhkeyreqLab(signal); return; }//if }//if }//Dblqh::rwConcludedAiLab() /* ########################################################################## * ####### LOG MODULE ####### * * ########################################################################## * -------------------------------------------------------------------------- * THE LOG MODULE HANDLES THE READING AND WRITING OF THE LOG * IT IS ALSO RESPONSIBLE FOR HANDLING THE SYSTEM RESTART. * IT CONTROLS THE SYSTEM RESTART IN TUP AND ACC AS WELL. * -------------------------------------------------------------------------- */ void Dblqh::logLqhkeyreqLab(Signal* signal) { UintR tcurrentFilepage; TcConnectionrecPtr tmpTcConnectptr; if (cnoOfLogPages < ZMIN_LOG_PAGES_OPERATION || ERROR_INSERTED(5032)) { jam(); if(ERROR_INSERTED(5032)){ CLEAR_ERROR_INSERT_VALUE; } /*---------------------------------------------------------------------------*/ // The log disk is having problems in catching up with the speed of execution. // We must wait with writing the log of this operation to ensure we do not // overload the log. /*---------------------------------------------------------------------------*/ terrorCode = ZTEMPORARY_REDO_LOG_FAILURE; abortErrorLab(signal); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; logPartPtr.i = regTcPtr->hashValue & 3; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); /* -------------------------------------------------- */ /* THIS PART IS USED TO WRITE THE LOG */ /* -------------------------------------------------- */ /* -------------------------------------------------- */ /* CHECK IF A LOG OPERATION IS ONGOING ALREADY. */ /* IF SO THEN QUEUE THE OPERATION FOR LATER */ /* RESTART WHEN THE LOG PART IS FREE AGAIN. */ /* -------------------------------------------------- */ LogPartRecord * const regLogPartPtr = logPartPtr.p; if(ERROR_INSERTED(5033)){ jam(); CLEAR_ERROR_INSERT_VALUE; if ((regLogPartPtr->firstLogQueue != RNIL) && (regLogPartPtr->LogLqhKeyReqSent == ZFALSE)) { /* -------------------------------------------------- */ /* WE HAVE A PROBLEM IN THAT THE LOG HAS NO */ /* ROOM FOR ADDITIONAL OPERATIONS AT THE MOMENT.*/ /* -------------------------------------------------- */ /* -------------------------------------------------- */ /* WE MUST STILL RESTART QUEUED OPERATIONS SO */ /* THEY ALSO CAN BE ABORTED. */ /* -------------------------------------------------- */ regLogPartPtr->LogLqhKeyReqSent = ZTRUE; signal->theData[0] = ZLOG_LQHKEYREQ; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if terrorCode = ZTAIL_PROBLEM_IN_LOG_ERROR; abortErrorLab(signal); return; } if (regLogPartPtr->logPartState == LogPartRecord::IDLE) { ; } else if (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) { jam(); linkWaitLog(signal, logPartPtr); regTcPtr->transactionState = TcConnectionrec::LOG_QUEUED; return; } else { if ((regLogPartPtr->firstLogQueue != RNIL) && (regLogPartPtr->LogLqhKeyReqSent == ZFALSE)) { /* -------------------------------------------------- */ /* WE HAVE A PROBLEM IN THAT THE LOG HAS NO */ /* ROOM FOR ADDITIONAL OPERATIONS AT THE MOMENT.*/ /* -------------------------------------------------- */ /* -------------------------------------------------- */ /* WE MUST STILL RESTART QUEUED OPERATIONS SO */ /* THEY ALSO CAN BE ABORTED. */ /* -------------------------------------------------- */ regLogPartPtr->LogLqhKeyReqSent = ZTRUE; signal->theData[0] = ZLOG_LQHKEYREQ; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if if (regLogPartPtr->logPartState == LogPartRecord::TAIL_PROBLEM) { jam(); terrorCode = ZTAIL_PROBLEM_IN_LOG_ERROR; } else { ndbrequire(regLogPartPtr->logPartState == LogPartRecord::FILE_CHANGE_PROBLEM); jam(); terrorCode = ZFILE_CHANGE_PROBLEM_IN_LOG_ERROR; }//if abortErrorLab(signal); return; }//if regLogPartPtr->logPartState = LogPartRecord::ACTIVE; logFilePtr.i = regLogPartPtr->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); /* -------------------------------------------------- */ /* CHECK IF A NEW MBYTE IS TO BE STARTED. IF */ /* SO INSERT A NEXT LOG RECORD, WRITE THE LOG */ /* AND PLACE THE LOG POINTER ON THE NEW POSITION*/ /* IF A NEW FILE IS TO BE USED, CHANGE FILE AND */ /* ALSO START OPENING THE NEXT LOG FILE. IF A */ /* LAP HAS BEEN COMPLETED THEN ADD ONE TO LAP */ /* COUNTER. */ /* -------------------------------------------------- */ checkNewMbyte(signal); /* -------------------------------------------------- */ /* INSERT THE OPERATION RECORD LAST IN THE LIST */ /* OF NOT COMPLETED OPERATIONS. ALSO RECORD THE */ /* FILE NO, PAGE NO AND PAGE INDEX OF THE START */ /* OF THIS LOG RECORD. */ /* IT IS NOT ALLOWED TO INSERT IT INTO THE LIST */ /* BEFORE CHECKING THE NEW MBYTE SINCE THAT WILL*/ /* CAUSE THE OLD VALUES OF TC_CONNECTPTR TO BE */ /* USED IN WRITE_FILE_DESCRIPTOR. */ /* -------------------------------------------------- */ Uint32 tcIndex = tcConnectptr.i; tmpTcConnectptr.i = regLogPartPtr->lastLogTcrec; regLogPartPtr->lastLogTcrec = tcIndex; if (tmpTcConnectptr.i == RNIL) { jam(); regLogPartPtr->firstLogTcrec = tcIndex; } else { ptrCheckGuard(tmpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); tmpTcConnectptr.p->nextLogTcrec = tcIndex; }//if Uint32 fileNo = logFilePtr.p->fileNo; tcurrentFilepage = logFilePtr.p->currentFilepage; logPagePtr.i = logFilePtr.p->currentLogpage; regTcPtr->nextLogTcrec = RNIL; regTcPtr->prevLogTcrec = tmpTcConnectptr.i; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); Uint32 pageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; regTcPtr->logStartFileNo = fileNo; regTcPtr->logStartPageNo = tcurrentFilepage; regTcPtr->logStartPageIndex = pageIndex; /* -------------------------------------------------- */ /* WRITE THE LOG HEADER OF THIS OPERATION. */ /* -------------------------------------------------- */ writeLogHeader(signal); /* -------------------------------------------------- */ /* WRITE THE TUPLE KEY OF THIS OPERATION. */ /* -------------------------------------------------- */ writeKey(signal); /* -------------------------------------------------- */ /* WRITE THE ATTRIBUTE INFO OF THIS OPERATION. */ /* -------------------------------------------------- */ writeAttrinfoLab(signal); logNextStart(signal); /* -------------------------------------------------- */ /* RESET THE STATE OF THE LOG PART. IF ANY */ /* OPERATIONS HAVE QUEUED THEN START THE FIRST */ /* OF THESE. */ /* -------------------------------------------------- */ /* -------------------------------------------------- */ /* CONTINUE WITH PACKING OF LQHKEYREQ */ /* -------------------------------------------------- */ tcurrentFilepage = logFilePtr.p->currentFilepage; if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) { jam(); tcurrentFilepage--; }//if regTcPtr->logStopPageNo = tcurrentFilepage; regTcPtr->logWriteState = TcConnectionrec::WRITTEN; if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { /* -------------------------------------------------- */ /* AN ABORT HAVE BEEN ORDERED. THE ABORT WAITED */ /* FOR THE LOG WRITE TO BE COMPLETED. NOW WE */ /* CAN PROCEED WITH THE NORMAL ABORT HANDLING. */ /* -------------------------------------------------- */ abortCommonLab(signal); return; }//if if (regTcPtr->dirtyOp != ZTRUE) { packLqhkeyreqLab(signal); } else { /* ---------------------------------------------------------------------- * I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS * TRANSACTION. SINCE WE RELEASED THE LOG LOCK JUST NOW NO ONE ELSE CAN BE * ACTIVE IN WRITING THE LOG. WE THUS WRITE THE LOG WITHOUT GETTING A LOCK * SINCE WE ARE ONLY WRITING A COMMIT LOG RECORD. * ---------------------------------------------------------------------- */ writeCommitLog(signal, logPartPtr); /* ---------------------------------------------------------------------- * DIRTY OPERATIONS SHOULD COMMIT BEFORE THEY PACK THE REQUEST/RESPONSE. * ---------------------------------------------------------------------- */ regTcPtr->gci = cnewestGci; localCommitLab(signal); }//if }//Dblqh::logLqhkeyreqLab() /* ------------------------------------------------------------------------- */ /* ------- SEND LQHKEYREQ */ /* */ /* NO STATE CHECKING SINCE THE SIGNAL IS A LOCAL SIGNAL. THE EXECUTION OF */ /* THE OPERATION IS COMPLETED. IT IS NOW TIME TO SEND THE OPERATION TO THE */ /* NEXT REPLICA OR TO TC. */ /* ------------------------------------------------------------------------- */ void Dblqh::packLqhkeyreqLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->nextReplica == ZNIL) { /* ------------------------------------------------------------------------- */ /* ------- SEND LQHKEYCONF ------- */ /* */ /* ------------------------------------------------------------------------- */ sendLqhkeyconfTc(signal, regTcPtr->tcBlockref); if (regTcPtr->dirtyOp != ZTRUE) { jam(); regTcPtr->transactionState = TcConnectionrec::PREPARED; releaseOprec(signal); } else { jam(); /*************************************************************>*/ /* DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST */ /* SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/ /* OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */ /* NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE */ /* SENT AS PART OF A COPY FRAGMENT PROCESS. */ /* */ /* DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING */ /* ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE */ /* LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE */ /* OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES */ /* ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT */ /* REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */ /* THOSE OPERATIONS ARE NOT INTERESTING. */ /* */ /* A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS */ /* IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */ /* ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */ /* THIS NODE. */ /*************************************************************>*/ cleanUp(signal); }//if return; }//if /* ------------------------------------------------------------------------- */ /* ------- SEND LQHKEYREQ ------- */ /* */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* THERE ARE MORE REPLICAS TO SEND THE OPERATION TO. A NEW LQHKEYREQ WILL BE */ /* PREPARED FOR THE NEXT REPLICA. */ /* ------------------------------------------------------------------------- */ /* CLEAR REPLICA TYPE, ATTRINFO INDICATOR (IN LQHKEYREQ), */ /* INTERPRETED EXECUTION, SEQUENTIAL NUMBER OF REPLICA. */ // Set bit indicating Client and TC record not the same. // Set readlenAi indicator if readlenAi != 0 // Stored Procedure Indicator not set. /* ------------------------------------------------------------------------- */ LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)&signal->theData[0]; UintR Treqinfo; UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6; Treqinfo = preComputedRequestInfoMask & regTcPtr->reqinfo; UintR TapplAddressIndicator = (regTcPtr->nextSeqNoReplica == 0 ? 0 : 1); LqhKeyReq::setApplicationAddressFlag(Treqinfo, TapplAddressIndicator); LqhKeyReq::setInterpretedFlag(Treqinfo, regTcPtr->opExec); LqhKeyReq::setSeqNoReplica(Treqinfo, regTcPtr->nextSeqNoReplica); LqhKeyReq::setAIInLqhKeyReq(Treqinfo, regTcPtr->reclenAiLqhkey); UintR TreadLenAiInd = (regTcPtr->readlenAi == 0 ? 0 : 1); UintR TsameLqhAndClient = (tcConnectptr.i == regTcPtr->tcOprec ? 0 : 1); LqhKeyReq::setSameClientAndTcFlag(Treqinfo, TsameLqhAndClient); LqhKeyReq::setReturnedReadLenAIFlag(Treqinfo, TreadLenAiInd); UintR TotReclenAi = regTcPtr->totSendlenAi; /* ------------------------------------------------------------------------- */ /* WE ARE NOW PREPARED TO SEND THE LQHKEYREQ. WE HAVE TO DECIDE IF ATTRINFO */ /* IS INCLUDED IN THE LQHKEYREQ SIGNAL AND THEN SEND IT. */ /* TAKE OVER SCAN OPERATION IS NEVER USED ON BACKUPS, LOG RECORDS AND START-UP*/ /* OF NEW REPLICA AND THUS ONLY TOT_SENDLEN_AI IS USED THE UPPER 16 BITS ARE */ /* ZERO. */ /* ------------------------------------------------------------------------- */ sig0 = tcConnectptr.i; sig1 = regTcPtr->savePointId; sig2 = regTcPtr->hashValue; sig4 = regTcPtr->tcBlockref; lqhKeyReq->clientConnectPtr = sig0; lqhKeyReq->attrLen = TotReclenAi; lqhKeyReq->savePointId = sig1; lqhKeyReq->hashValue = sig2; lqhKeyReq->requestInfo = Treqinfo; lqhKeyReq->tcBlockref = sig4; sig0 = regTcPtr->tableref + (regTcPtr->schemaVersion << 16); sig1 = regTcPtr->fragmentid + (regTcPtr->nodeAfterNext[0] << 16); sig2 = regTcPtr->transid[0]; sig3 = regTcPtr->transid[1]; sig4 = regTcPtr->applRef; sig5 = regTcPtr->applOprec; sig6 = regTcPtr->tcOprec; UintR nextPos = (TapplAddressIndicator << 1); lqhKeyReq->tableSchemaVersion = sig0; lqhKeyReq->fragmentData = sig1; lqhKeyReq->transId1 = sig2; lqhKeyReq->transId2 = sig3; lqhKeyReq->noFiredTriggers = regTcPtr->noFiredTriggers; lqhKeyReq->variableData[0] = sig4; lqhKeyReq->variableData[1] = sig5; lqhKeyReq->variableData[2] = sig6; nextPos += TsameLqhAndClient; if ((regTcPtr->lastReplicaNo - regTcPtr->nextSeqNoReplica) > 1) { sig0 = (UintR)regTcPtr->nodeAfterNext[1] + (UintR)(regTcPtr->nodeAfterNext[2] << 16); lqhKeyReq->variableData[nextPos] = sig0; nextPos++; }//if sig0 = regTcPtr->readlenAi; sig1 = regTcPtr->tupkeyData[0]; sig2 = regTcPtr->tupkeyData[1]; sig3 = regTcPtr->tupkeyData[2]; sig4 = regTcPtr->tupkeyData[3]; lqhKeyReq->variableData[nextPos] = sig0; nextPos += TreadLenAiInd; lqhKeyReq->variableData[nextPos] = sig1; lqhKeyReq->variableData[nextPos + 1] = sig2; lqhKeyReq->variableData[nextPos + 2] = sig3; lqhKeyReq->variableData[nextPos + 3] = sig4; UintR TkeyLen = LqhKeyReq::getKeyLen(Treqinfo); if (TkeyLen < 4) { nextPos += TkeyLen; } else { nextPos += 4; }//if sig0 = regTcPtr->firstAttrinfo[0]; sig1 = regTcPtr->firstAttrinfo[1]; sig2 = regTcPtr->firstAttrinfo[2]; sig3 = regTcPtr->firstAttrinfo[3]; sig4 = regTcPtr->firstAttrinfo[4]; UintR TAiLen = regTcPtr->reclenAiLqhkey; BlockReference lqhRef = calcLqhBlockRef(regTcPtr->nextReplica); lqhKeyReq->variableData[nextPos] = sig0; lqhKeyReq->variableData[nextPos + 1] = sig1; lqhKeyReq->variableData[nextPos + 2] = sig2; lqhKeyReq->variableData[nextPos + 3] = sig3; lqhKeyReq->variableData[nextPos + 4] = sig4; nextPos += TAiLen; sendSignal(lqhRef, GSN_LQHKEYREQ, signal, nextPos + LqhKeyReq::FixedSignalLength, JBB); if (regTcPtr->primKeyLen > 4) { jam(); /* ------------------------------------------------------------------------- */ /* MORE THAN 4 WORDS OF KEY DATA IS IN THE OPERATION. THEREFORE WE NEED TO */ /* PREPARE A KEYINFO SIGNAL. MORE THAN ONE KEYINFO SIGNAL CAN BE SENT. */ /* ------------------------------------------------------------------------- */ sendTupkey(signal); }//if /* ------------------------------------------------------------------------- */ /* NOW I AM PREPARED TO SEND ALL THE ATTRINFO SIGNALS. AT THE MOMENT A LOOP */ /* SENDS ALL AT ONCE. LATER WE HAVE TO ADDRESS THE PROBLEM THAT THESE COULD */ /* LEAD TO BUFFER EXPLOSION => NODE CRASH. */ /* ------------------------------------------------------------------------- */ /* NEW CODE TO SEND ATTRINFO IN PACK_LQHKEYREQ */ /* THIS CODE USES A REAL-TIME BREAK AFTER */ /* SENDING 16 SIGNALS. */ /* -------------------------------------------------- */ sig0 = regTcPtr->tcOprec; sig1 = regTcPtr->transid[0]; sig2 = regTcPtr->transid[1]; signal->theData[0] = sig0; signal->theData[1] = sig1; signal->theData[2] = sig2; AttrbufPtr regAttrinbufptr; regAttrinbufptr.i = regTcPtr->firstAttrinbuf; while (regAttrinbufptr.i != RNIL) { ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); jam(); Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; ndbrequire(dataLen != 0); MEMCOPY_NO_WORDS(&signal->theData[3], ®Attrinbufptr.p->attrbuf[0], dataLen); regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; sendSignal(lqhRef, GSN_ATTRINFO, signal, dataLen + 3, JBB); }//while regTcPtr->transactionState = TcConnectionrec::PREPARED; if (regTcPtr->dirtyOp == ZTRUE) { jam(); /*************************************************************>*/ /* DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST */ /* SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/ /* OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */ /* NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE */ /* SENT AS PART OF A COPY FRAGMENT PROCESS. */ /* */ /* DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING */ /* ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE */ /* LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE */ /* OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES */ /* ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT */ /* REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */ /* THOSE OPERATIONS ARE NOT INTERESTING. */ /* */ /* A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS */ /* IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */ /* ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */ /* THIS NODE. */ /*************************************************************>*/ cleanUp(signal); return; }//if /* ------------------------------------------------------------------------ * ALL INFORMATION NEEDED BY THE COMMIT PHASE AND COMPLETE PHASE IS * KEPT IN THE TC_CONNECT RECORD. TO ENSURE PROPER USE OF MEMORY * RESOURCES WE DEALLOCATE THE ATTRINFO RECORD AND KEY RECORDS * AS SOON AS POSSIBLE. * ------------------------------------------------------------------------ */ releaseOprec(signal); }//Dblqh::packLqhkeyreqLab() /* ========================================================================= */ /* ==== CHECK IF THE LOG RECORD FITS INTO THE CURRENT MBYTE, ======= */ /* OTHERWISE SWITCH TO NEXT MBYTE. */ /* */ /* ========================================================================= */ void Dblqh::checkNewMbyte(Signal* signal) { UintR tcnmTmp; UintR ttotalLogSize; /* -------------------------------------------------- */ /* CHECK IF A NEW MBYTE OF LOG RECORD IS TO BE */ /* OPENED BEFORE WRITING THE LOG RECORD. NO LOG */ /* RECORDS ARE ALLOWED TO SPAN A MBYTE BOUNDARY */ /* */ /* INPUT: TC_CONNECTPTR THE OPERATION */ /* LOG_FILE_PTR THE LOG FILE */ /* OUTPUT: LOG_FILE_PTR THE NEW LOG FILE */ /* -------------------------------------------------- */ ttotalLogSize = ZLOG_HEAD_SIZE + tcConnectptr.p->currTupAiLen; ttotalLogSize = ttotalLogSize + tcConnectptr.p->primKeyLen; tcnmTmp = logFilePtr.p->remainingWordsInMbyte; if ((ttotalLogSize + ZNEXT_LOG_SIZE) <= tcnmTmp) { ndbrequire(tcnmTmp >= ttotalLogSize); logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize; return; } else { jam(); /* -------------------------------------------------- */ /* IT WAS NOT ENOUGH SPACE IN THIS MBYTE FOR */ /* THIS LOG RECORD. MOVE TO NEXT MBYTE */ /* THIS MIGHT INCLUDE CHANGING LOG FILE */ /* -------------------------------------------------- */ /* WE HAVE TO INSERT A NEXT LOG RECORD FIRST */ /* -------------------------------------------------- */ /* THEN CONTINUE BY WRITING THE FILE DESCRIPTORS*/ /* -------------------------------------------------- */ logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); changeMbyte(signal); tcnmTmp = logFilePtr.p->remainingWordsInMbyte; }//if ndbrequire(tcnmTmp >= ttotalLogSize); logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize; }//Dblqh::checkNewMbyte() /* -------------------------------------------------------------------------- * ------- WRITE OPERATION HEADER TO LOG ------- * * SUBROUTINE SHORT NAME: WLH * ------------------------------------------------------------------------- */ void Dblqh::writeLogHeader(Signal* signal) { Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; Uint32 hashValue = tcConnectptr.p->hashValue; Uint32 operation = tcConnectptr.p->operation; Uint32 keyLen = tcConnectptr.p->primKeyLen; Uint32 aiLen = tcConnectptr.p->currTupAiLen; Uint32 totLogLen = aiLen + keyLen + ZLOG_HEAD_SIZE; if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) { Uint32* dataPtr = &logPagePtr.p->logPageWord[logPos]; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE; dataPtr[0] = ZPREP_OP_TYPE; dataPtr[1] = totLogLen; dataPtr[2] = hashValue; dataPtr[3] = operation; dataPtr[4] = aiLen; dataPtr[5] = keyLen; } else { writeLogWord(signal, ZPREP_OP_TYPE); writeLogWord(signal, totLogLen); writeLogWord(signal, hashValue); writeLogWord(signal, operation); writeLogWord(signal, aiLen); writeLogWord(signal, keyLen); }//if }//Dblqh::writeLogHeader() /* -------------------------------------------------------------------------- * ------- WRITE TUPLE KEY TO LOG ------- * * SUBROUTINE SHORT NAME: WK * ------------------------------------------------------------------------- */ void Dblqh::writeKey(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 logPos, endPos, dataLen; Int32 remainingLen; logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; remainingLen = regTcPtr->primKeyLen; dataLen = remainingLen; if (remainingLen > 4) dataLen = 4; remainingLen -= dataLen; endPos = logPos + dataLen; if (endPos < ZPAGE_SIZE) { MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], ®TcPtr->tupkeyData[0], dataLen); } else { jam(); for (Uint32 i = 0; i < dataLen; i++) writeLogWord(signal, regTcPtr->tupkeyData[i]); endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; }//if DatabufPtr regDatabufptr; regDatabufptr.i = regTcPtr->firstTupkeybuf; while (remainingLen > 0) { logPos = endPos; ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); dataLen = remainingLen; if (remainingLen > 4) dataLen = 4; remainingLen -= dataLen; endPos += dataLen; if (endPos < ZPAGE_SIZE) { MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], ®Databufptr.p->data[0], dataLen); } else { logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; for (Uint32 i = 0; i < dataLen; i++) writeLogWord(signal, regDatabufptr.p->data[i]); endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; }//if regDatabufptr.i = regDatabufptr.p->nextDatabuf; }//while logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = endPos; ndbrequire(regDatabufptr.i == RNIL); }//Dblqh::writeKey() /* -------------------------------------------------------------------------- * ------- WRITE ATTRINFO TO LOG ------- * * SUBROUTINE SHORT NAME: WA * ------------------------------------------------------------------------- */ void Dblqh::writeAttrinfoLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 totLen = regTcPtr->currTupAiLen; if (totLen == 0) return; Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; Uint32 lqhLen = regTcPtr->reclenAiLqhkey; ndbrequire(totLen >= lqhLen); Uint32 endPos = logPos + lqhLen; totLen -= lqhLen; if (endPos < ZPAGE_SIZE) { MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], ®TcPtr->firstAttrinfo[0], lqhLen); } else { for (Uint32 i = 0; i < lqhLen; i++) writeLogWord(signal, regTcPtr->firstAttrinfo[i]); endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; }//if AttrbufPtr regAttrinbufptr; regAttrinbufptr.i = regTcPtr->firstAttrinbuf; while (totLen > 0) { logPos = endPos; ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; ndbrequire(totLen >= dataLen); ndbrequire(dataLen > 0); totLen -= dataLen; endPos += dataLen; if (endPos < ZPAGE_SIZE) { MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], ®Attrinbufptr.p->attrbuf[0], dataLen); } else { logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; for (Uint32 i = 0; i < dataLen; i++) writeLogWord(signal, regAttrinbufptr.p->attrbuf[i]); endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; }//if regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; }//while logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = endPos; ndbrequire(regAttrinbufptr.i == RNIL); }//Dblqh::writeAttrinfoLab() /* ------------------------------------------------------------------------- */ /* ------- SEND TUPLE KEY IN KEYINFO SIGNAL(S) ------- */ /* */ /* SUBROUTINE SHORT NAME: STU */ /* ------------------------------------------------------------------------- */ void Dblqh::sendTupkey(Signal* signal) { UintR TdataPos = 3; BlockReference lqhRef = calcLqhBlockRef(tcConnectptr.p->nextReplica); signal->theData[0] = tcConnectptr.p->tcOprec; signal->theData[1] = tcConnectptr.p->transid[0]; signal->theData[2] = tcConnectptr.p->transid[1]; databufptr.i = tcConnectptr.p->firstTupkeybuf; do { ptrCheckGuard(databufptr, cdatabufFileSize, databuf); signal->theData[TdataPos] = databufptr.p->data[0]; signal->theData[TdataPos + 1] = databufptr.p->data[1]; signal->theData[TdataPos + 2] = databufptr.p->data[2]; signal->theData[TdataPos + 3] = databufptr.p->data[3]; databufptr.i = databufptr.p->nextDatabuf; TdataPos += 4; if (databufptr.i == RNIL) { jam(); sendSignal(lqhRef, GSN_KEYINFO, signal, TdataPos, JBB); return; } else if (TdataPos == 23) { jam(); sendSignal(lqhRef, GSN_KEYINFO, signal, 23, JBB); TdataPos = 3; } } while (1); }//Dblqh::sendTupkey() void Dblqh::cleanUp(Signal* signal) { releaseOprec(signal); deleteTransidHash(signal); releaseTcrec(signal, tcConnectptr); }//Dblqh::cleanUp() /* -------------------------------------------------------------------------- * ---- RELEASE ALL RECORDS CONNECTED TO THE OPERATION RECORD AND THE ---- * OPERATION RECORD ITSELF * ------------------------------------------------------------------------- */ void Dblqh::releaseOprec(Signal* signal) { UintR Tmpbuf; TcConnectionrec * const regTcPtr = tcConnectptr.p; /* ---- RELEASE DATA BUFFERS ------------------- */ DatabufPtr regDatabufptr; regDatabufptr.i = regTcPtr->firstTupkeybuf; /* -------------------------------------------------------------------------- * ------- RELEASE DATA BUFFERS ------- * * ------------------------------------------------------------------------- */ while (regDatabufptr.i != RNIL) { jam(); ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); Tmpbuf = regDatabufptr.p->nextDatabuf; regDatabufptr.p->nextDatabuf = cfirstfreeDatabuf; cfirstfreeDatabuf = regDatabufptr.i; regDatabufptr.i = Tmpbuf; }//while /* ---- RELEASE ATTRINFO BUFFERS ------------------- */ AttrbufPtr regAttrinbufptr; regAttrinbufptr.i = regTcPtr->firstAttrinbuf; /* ######################################################################## * ####### RELEASE_ATTRINBUF ####### * * ####################################################################### */ while (regAttrinbufptr.i != RNIL) { jam(); regAttrinbufptr.i= release_attrinbuf(regAttrinbufptr.i); }//while regTcPtr->firstAttrinbuf = RNIL; regTcPtr->lastAttrinbuf = RNIL; regTcPtr->firstTupkeybuf = RNIL; regTcPtr->lastTupkeybuf = RNIL; }//Dblqh::releaseOprec() /* ------------------------------------------------------------------------- */ /* ------ DELETE TRANSACTION ID FROM HASH TABLE ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::deleteTransidHash(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; TcConnectionrecPtr prevHashptr; TcConnectionrecPtr nextHashptr; prevHashptr.i = regTcPtr->prevHashRec; nextHashptr.i = regTcPtr->nextHashRec; if (prevHashptr.i != RNIL) { jam(); ptrCheckGuard(prevHashptr, ctcConnectrecFileSize, tcConnectionrec); prevHashptr.p->nextHashRec = nextHashptr.i; } else { jam(); /* ------------------------------------------------------------------------- */ /* THE OPERATION WAS PLACED FIRST IN THE LIST OF THE HASH TABLE. NEED TO SET */ /* A NEW LEADER OF THE LIST. */ /* ------------------------------------------------------------------------- */ Uint32 hashIndex = (regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023; ctransidHash[hashIndex] = nextHashptr.i; }//if if (nextHashptr.i != RNIL) { jam(); ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec); nextHashptr.p->prevHashRec = prevHashptr.i; }//if }//Dblqh::deleteTransidHash() /* -------------------------------------------------------------------------- * ------- LINK OPERATION IN ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME: LAF // Input Pointers: // tcConnectptr // fragptr * ------------------------------------------------------------------------- */ void Dblqh::linkActiveFrag(Signal* signal) { TcConnectionrecPtr lafTcConnectptr; TcConnectionrec * const regTcPtr = tcConnectptr.p; Fragrecord * const regFragPtr = fragptr.p; Uint32 tcIndex = tcConnectptr.i; lafTcConnectptr.i = regFragPtr->activeList; regTcPtr->prevTc = RNIL; regFragPtr->activeList = tcIndex; ndbrequire(regTcPtr->listState == TcConnectionrec::NOT_IN_LIST); regTcPtr->nextTc = lafTcConnectptr.i; regTcPtr->listState = TcConnectionrec::IN_ACTIVE_LIST; if (lafTcConnectptr.i == RNIL) { return; } else { jam(); ptrCheckGuard(lafTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); lafTcConnectptr.p->prevTc = tcIndex; }//if return; }//Dblqh::linkActiveFrag() /* ------------------------------------------------------------------------- * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME = RAF * ------------------------------------------------------------------------- */ void Dblqh::releaseActiveFrag(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; TcConnectionrecPtr ralTcNextConnectptr; TcConnectionrecPtr ralTcPrevConnectptr; fragptr.i = regTcPtr->fragmentptr; ralTcPrevConnectptr.i = regTcPtr->prevTc; ralTcNextConnectptr.i = regTcPtr->nextTc; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); Fragrecord * const regFragPtr = fragptr.p; ndbrequire(regTcPtr->listState == TcConnectionrec::IN_ACTIVE_LIST); regTcPtr->listState = TcConnectionrec::NOT_IN_LIST; if (ralTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(ralTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); ralTcNextConnectptr.p->prevTc = ralTcPrevConnectptr.i; }//if if (ralTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(ralTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); ralTcPrevConnectptr.p->nextTc = regTcPtr->nextTc; } else { jam(); /* ---------------------------------------------------------------------- * OPERATION RECORD IS FIRST IN ACTIVE LIST * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. * --------------------------------------------------------------------- */ regFragPtr->activeList = ralTcNextConnectptr.i; }//if if (regFragPtr->lcpRef != RNIL) { jam(); lcpPtr.i = regFragPtr->lcpRef; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_ACTIVE_FINISH); /* -------------------------------------------------------------------- * IF A FRAGMENT IS CURRENTLY STARTING A LOCAL CHECKPOINT AND IT * IS WAITING FOR ACTIVE OPERATIONS TO BE COMPLETED WITH THE * CURRENT PHASE, THEN IT IS CHECKED WHETHER THE * LAST ACTIVE OPERATION WAS NOW COMPLETED. * ------------------------------------------------------------------- */ if (regFragPtr->activeList == RNIL) { jam(); /* ------------------------------------------------------------------ * ACTIVE LIST ON FRAGMENT IS EMPTY AND WE ARE WAITING FOR * THIS TO HAPPEN. * WE WILL NOW START THE CHECKPOINT IN TUP AND ACC. * ----------------------------------------------------------------- */ /* SEND START LOCAL CHECKPOINT TO ACC AND TUP */ /* ----------------------------------------------------------------- */ fragptr.p->lcpRef = RNIL; lcpPtr.p->lcpState = LcpRecord::LCP_START_CHKP; sendStartLcp(signal); }//if }//if }//Dblqh::releaseActiveFrag() /* ######################################################################### */ /* ####### TRANSACTION MODULE ####### */ /* THIS MODULE HANDLES THE COMMIT AND THE COMPLETE PHASE. */ /* ######################################################################### */ void Dblqh::warningReport(Signal* signal, int place) { switch (place) { case 0: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMMIT in wrong state in Dblqh" << endl; #endif break; case 1: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMMIT with wrong transid in Dblqh" << endl; #endif break; case 2: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMPLETE in wrong state in Dblqh" << endl; #endif break; case 3: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMPLETE with wrong transid in Dblqh" << endl; #endif break; case 4: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMMITREQ in wrong state in Dblqh" << endl; #endif break; case 5: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMMITREQ with wrong transid in Dblqh" << endl; #endif break; case 6: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMPLETEREQ in wrong state in Dblqh" << endl; #endif break; case 7: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMPLETEREQ with wrong transid in Dblqh" << endl; #endif break; case 8: jam(); #ifdef ABORT_TRACE ndbout << "W: Received ABORT with non-existing transid in Dblqh" << endl; #endif break; case 9: jam(); #ifdef ABORT_TRACE ndbout << "W: Received ABORTREQ with non-existing transid in Dblqh" << endl; #endif break; case 10: jam(); #ifdef ABORT_TRACE ndbout << "W: Received ABORTREQ in wrong state in Dblqh" << endl; #endif break; case 11: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMMIT when tc-rec released in Dblqh" << endl; #endif break; case 12: jam(); #ifdef ABORT_TRACE ndbout << "W: Received COMPLETE when tc-rec released in Dblqh" << endl; #endif break; case 13: jam(); #ifdef ABORT_TRACE ndbout << "W: Received LQHKEYREF when tc-rec released in Dblqh" << endl; #endif break; case 14: jam(); #ifdef ABORT_TRACE ndbout << "W: Received LQHKEYREF with wrong transid in Dblqh" << endl; #endif break; case 15: jam(); #ifdef ABORT_TRACE ndbout << "W: Received LQHKEYREF when already aborting in Dblqh" << endl; #endif break; case 16: jam(); ndbrequire(cstartPhase == ZNIL); #ifdef ABORT_TRACE ndbout << "W: Received LQHKEYREF in wrong state in Dblqh" << endl; #endif break; default: jam(); break; }//switch return; }//Dblqh::warningReport() void Dblqh::errorReport(Signal* signal, int place) { switch (place) { case 0: jam(); break; case 1: jam(); break; case 2: jam(); break; case 3: jam(); break; default: jam(); break; }//switch systemErrorLab(signal); return; }//Dblqh::errorReport() /* ************************************************************************>> * COMMIT: Start commit request from TC. This signal is originally sent as a * packed signal and this function is called from execPACKED_SIGNAL. * This is the normal commit protocol where TC first send this signal to the * backup node which then will send COMMIT to the primary node. If * everything is ok the primary node send COMMITTED back to TC. * ************************************************************************>> */ void Dblqh::execCOMMIT(Signal* signal) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; Uint32 tcIndex = signal->theData[0]; Uint32 gci = signal->theData[1]; Uint32 transid1 = signal->theData[2]; Uint32 transid2 = signal->theData[3]; jamEntry(); if (tcIndex >= ttcConnectrecFileSize) { errorReport(signal, 0); return; }//if if (ERROR_INSERTED(5011)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000, 4); return; }//if if (ERROR_INSERTED(5012)) { SET_ERROR_INSERT_VALUE(5017); sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000, 4); return; }//if tcConnectptr.i = tcIndex; ptrAss(tcConnectptr, regTcConnectionrec); if ((tcConnectptr.p->transid[0] == transid1) && (tcConnectptr.p->transid[1] == transid2)) { commitReqLab(signal, gci); return; }//if warningReport(signal, 1); return; }//Dblqh::execCOMMIT() /* ************************************************************************>> * COMMITREQ: Commit request from TC. This is the commit protocol used if * one of the nodes is not behaving correctly. TC explicitly sends COMMITREQ * to both the backup and primary node and gets a COMMITCONF back if the * COMMIT was ok. * ************************************************************************>> */ void Dblqh::execCOMMITREQ(Signal* signal) { jamEntry(); Uint32 reqPtr = signal->theData[0]; BlockReference reqBlockref = signal->theData[1]; Uint32 gci = signal->theData[2]; Uint32 transid1 = signal->theData[3]; Uint32 transid2 = signal->theData[4]; Uint32 tcOprec = signal->theData[6]; if (ERROR_INSERTED(5004)) { systemErrorLab(signal); } if (ERROR_INSERTED(5017)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMMITREQ, signal, 2000, 7); return; }//if if (findTransaction(transid1, transid2, tcOprec) != ZOK) { warningReport(signal, 5); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; switch (regTcPtr->transactionState) { case TcConnectionrec::PREPARED: case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL: jam(); /*-------------------------------------------------------*/ /* THE NORMAL CASE. */ /*-------------------------------------------------------*/ regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; commitReqLab(signal, gci); return; break; case TcConnectionrec::COMMITTED: jam(); /*---------------------------------------------------------*/ /* FOR SOME REASON THE COMMIT PHASE HAVE BEEN */ /* FINISHED AFTER A TIME OUT. WE NEED ONLY SEND A */ /* COMMITCONF SIGNAL. */ /*---------------------------------------------------------*/ regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; signal->theData[0] = regTcPtr->reqRef; signal->theData[1] = cownNodeid; signal->theData[2] = regTcPtr->transid[0]; signal->theData[3] = regTcPtr->transid[1]; sendSignal(regTcPtr->reqBlockref, GSN_COMMITCONF, signal, 4, JBB); break; case TcConnectionrec::COMMIT_STOPPED: jam(); regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; /*empty*/; break; default: jam(); warningReport(signal, 4); return; break; }//switch return; }//Dblqh::execCOMMITREQ() /* ************************************************************************>> * COMPLETE : Complete the transaction. Sent as a packed signal from TC. * Works the same way as COMMIT protocol. This is the normal case with both * primary and backup working (See COMMIT). * ************************************************************************>> */ void Dblqh::execCOMPLETE(Signal* signal) { TcConnectionrec *regTcConnectionrec = tcConnectionrec; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; Uint32 tcIndex = signal->theData[0]; Uint32 transid1 = signal->theData[1]; Uint32 transid2 = signal->theData[2]; jamEntry(); if (tcIndex >= ttcConnectrecFileSize) { errorReport(signal, 1); return; }//if if (ERROR_INSERTED(5013)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3); return; }//if if (ERROR_INSERTED(5014)) { SET_ERROR_INSERT_VALUE(5018); sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3); return; }//if tcConnectptr.i = tcIndex; ptrAss(tcConnectptr, regTcConnectionrec); if ((tcConnectptr.p->transactionState == TcConnectionrec::COMMITTED) && (tcConnectptr.p->transid[0] == transid1) && (tcConnectptr.p->transid[1] == transid2)) { if (tcConnectptr.p->seqNoReplica != 0) { jam(); localCommitLab(signal); return; } else { jam(); completeTransLastLab(signal); return; }//if }//if if (tcConnectptr.p->transactionState != TcConnectionrec::COMMITTED) { warningReport(signal, 2); } else { warningReport(signal, 3); }//if }//Dblqh::execCOMPLETE() /* ************************************************************************>> * COMPLETEREQ: Complete request from TC. Same as COMPLETE but used if one * node is not working ok (See COMMIT). * ************************************************************************>> */ void Dblqh::execCOMPLETEREQ(Signal* signal) { jamEntry(); Uint32 reqPtr = signal->theData[0]; BlockReference reqBlockref = signal->theData[1]; Uint32 transid1 = signal->theData[2]; Uint32 transid2 = signal->theData[3]; Uint32 tcOprec = signal->theData[5]; if (ERROR_INSERTED(5005)) { systemErrorLab(signal); } if (ERROR_INSERTED(5018)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_COMPLETEREQ, signal, 2000, 6); return; }//if if (findTransaction(transid1, transid2, tcOprec) != ZOK) { jam(); /*---------------------------------------------------------*/ /* FOR SOME REASON THE COMPLETE PHASE STARTED AFTER */ /* A TIME OUT. THE TRANSACTION IS GONE. WE NEED TO */ /* REPORT COMPLETION ANYWAY. */ /*---------------------------------------------------------*/ signal->theData[0] = reqPtr; signal->theData[1] = cownNodeid; signal->theData[2] = transid1; signal->theData[3] = transid2; sendSignal(reqBlockref, GSN_COMPLETECONF, signal, 4, JBB); warningReport(signal, 7); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; switch (regTcPtr->transactionState) { case TcConnectionrec::COMMITTED: jam(); regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; /*empty*/; break; /*---------------------------------------------------------*/ /* THE NORMAL CASE. */ /*---------------------------------------------------------*/ case TcConnectionrec::COMMIT_STOPPED: jam(); /*---------------------------------------------------------*/ /* FOR SOME REASON THE COMPLETE PHASE STARTED AFTER */ /* A TIME OUT. WE HAVE SET THE PROPER VARIABLES SUCH */ /* THAT A COMPLETECONF WILL BE SENT WHEN COMPLETE IS */ /* FINISHED. */ /*---------------------------------------------------------*/ regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; return; break; default: jam(); warningReport(signal, 6); return; break; }//switch if (regTcPtr->seqNoReplica != 0) { jam(); localCommitLab(signal); return; } else { jam(); completeTransLastLab(signal); return; }//if }//Dblqh::execCOMPLETEREQ() /* ************> */ /* COMPLETED > */ /* ************> */ void Dblqh::execLQHKEYCONF(Signal* signal) { LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); Uint32 tcIndex = lqhKeyConf->opPtr; Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; TcConnectionrec *regTcConnectionrec = tcConnectionrec; jamEntry(); if (tcIndex >= ttcConnectrecFileSize) { errorReport(signal, 2); return; }//if tcConnectptr.i = tcIndex; ptrAss(tcConnectptr, regTcConnectionrec); switch (tcConnectptr.p->connectState) { case TcConnectionrec::LOG_CONNECTED: jam(); completedLab(signal); return; break; case TcConnectionrec::COPY_CONNECTED: jam(); copyCompletedLab(signal); return; break; default: jam(); ndbrequire(false); break; }//switch return; }//Dblqh::execLQHKEYCONF() /* ------------------------------------------------------------------------- */ /* ------- COMMIT PHASE ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::commitReqLab(Signal* signal, Uint32 gci) { TcConnectionrec * const regTcPtr = tcConnectptr.p; TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState; TcConnectionrec::TransactionState transState = regTcPtr->transactionState; regTcPtr->gci = gci; if (transState == TcConnectionrec::PREPARED) { if (logWriteState == TcConnectionrec::WRITTEN) { jam(); regTcPtr->transactionState = TcConnectionrec::PREPARED_RECEIVED_COMMIT; TcConnectionrecPtr saveTcPtr = tcConnectptr; Uint32 blockNo = refToBlock(regTcPtr->tcTupBlockref); signal->theData[0] = regTcPtr->tupConnectrec; signal->theData[1] = gci; EXECUTE_DIRECT(blockNo, GSN_TUP_WRITELOG_REQ, signal, 2); jamEntry(); if (regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) { jam(); return; }//if ndbrequire(regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_WRITTEN); tcConnectptr = saveTcPtr; } else if (logWriteState == TcConnectionrec::NOT_STARTED) { jam(); } else if (logWriteState == TcConnectionrec::NOT_WRITTEN) { jam(); /*---------------------------------------------------------------------------*/ /* IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE. THIS CAN OCCUR */ /* WHEN WE ARE STARTING A NEW FRAGMENT. */ /*---------------------------------------------------------------------------*/ regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; } else { ndbrequire(logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT); jam(); /*---------------------------------------------------------------------------*/ /* THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER A SCAN OF ALL */ /* OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT. THIS INDICATES THAT WE */ /* ARE WAITING FOR THIS OPERATION TO COMMIT OR ABORT SO THAT WE CAN FIND THE */ /* STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT. */ /*---------------------------------------------------------------------------*/ checkScanTcCompleted(signal); }//if } else if (transState == TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL) { jam(); regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED; return; } else if (transState == TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL) { jam(); } else { warningReport(signal, 0); return; }//if if (regTcPtr->seqNoReplica != 0) { jam(); commitReplyLab(signal); return; }//if localCommitLab(signal); return; }//Dblqh::commitReqLab() void Dblqh::execLQH_WRITELOG_REQ(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 gci = signal->theData[1]; Uint32 newestGci = cnewestGci; TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState; TcConnectionrec::TransactionState transState = regTcPtr->transactionState; regTcPtr->gci = gci; if (gci > newestGci) { jam(); /* ------------------------------------------------------------------------- */ /* KEEP TRACK OF NEWEST GLOBAL CHECKPOINT THAT LQH HAS HEARD OF. */ /* ------------------------------------------------------------------------- */ cnewestGci = gci; }//if if (logWriteState == TcConnectionrec::WRITTEN) { /*---------------------------------------------------------------------------*/ /* I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS */ /* TRANSACTION. */ /*---------------------------------------------------------------------------*/ jam(); LogPartRecordPtr regLogPartPtr; Uint32 noOfLogPages = cnoOfLogPages; jam(); regLogPartPtr.i = regTcPtr->hashValue & 3; ptrCheckGuard(regLogPartPtr, clogPartFileSize, logPartRecord); if ((regLogPartPtr.p->logPartState == LogPartRecord::ACTIVE) || (noOfLogPages == 0)) { jam(); /*---------------------------------------------------------------------------*/ /* THIS LOG PART WAS CURRENTLY ACTIVE WRITING ANOTHER LOG RECORD. WE MUST */ /* WAIT UNTIL THIS PART HAS COMPLETED ITS OPERATION. */ /*---------------------------------------------------------------------------*/ // We must delay the write of commit info to the log to safe-guard against // a crash due to lack of log pages. We temporary stop all log writes to this // log part to ensure that we don't get a buffer explosion in the delayed // signal buffer instead. /*---------------------------------------------------------------------------*/ linkWaitLog(signal, regLogPartPtr); if (transState == TcConnectionrec::PREPARED) { jam(); regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL; } else { jam(); ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT); regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED; }//if if (regLogPartPtr.p->logPartState == LogPartRecord::IDLE) { jam(); regLogPartPtr.p->logPartState = LogPartRecord::ACTIVE; }//if return; }//if writeCommitLog(signal, regLogPartPtr); if (transState == TcConnectionrec::PREPARED) { jam(); regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL; } else { jam(); ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT); regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN; }//if }//if }//Dblqh::execLQH_WRITELOG_REQ() void Dblqh::localCommitLab(Signal* signal) { FragrecordPtr regFragptr; regFragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); Fragrecord::FragStatus status = regFragptr.p->fragStatus; fragptr = regFragptr; switch (status) { case Fragrecord::FSACTIVE: case Fragrecord::CRASH_RECOVERING: case Fragrecord::ACTIVE_CREATION: jam(); commitContinueAfterBlockedLab(signal); return; break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::COMMIT_STOPPED; break; case Fragrecord::FREE: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); break; }//switch }//Dblqh::localCommitLab() void Dblqh::commitContinueAfterBlockedLab(Signal* signal) { /* ------------------------------------------------------------------------- */ /*INPUT: TC_CONNECTPTR ACTIVE OPERATION RECORD */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /*CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT. */ /*The operation is already removed from the active list since there is no */ /*chance for any real-time breaks before we need to release it. */ /* ------------------------------------------------------------------------- */ /*ALSO AFTER NORMAL PROCEDURE WE CONTINUE */ /*WE MUST COMMIT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN AND SEES A */ /*DIRTY STATE IN TUP. */ /* ------------------------------------------------------------------------- */ TcConnectionrec * const regTcPtr = tcConnectptr.p; Fragrecord * const regFragptr = fragptr.p; Uint32 operation = regTcPtr->operation; if (regTcPtr->activeCreat == ZFALSE) { if ((cCommitBlocked == true) && (regFragptr->fragActiveStatus == ZTRUE)) { jam(); /* ------------------------------------------------------------------------- */ // TUP and/or ACC have problems in writing the undo log to disk fast enough. // We must avoid the commit at this time and try later instead. The fragment // is also active with a local checkpoint and this commit can generate UNDO // log records that overflow the UNDO log buffer. /* ------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------*/ // We must delay the write of commit info to the log to safe-guard against // a crash due to lack of log pages. We temporary stop all log writes to this // log part to ensure that we don't get a buffer explosion in the delayed // signal buffer instead. /*---------------------------------------------------------------------------*/ logPartPtr.i = regTcPtr->hashValue & 3; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); linkWaitLog(signal, logPartPtr); regTcPtr->transactionState = TcConnectionrec::COMMIT_QUEUED; if (logPartPtr.p->logPartState == LogPartRecord::IDLE) { jam(); logPartPtr.p->logPartState = LogPartRecord::ACTIVE; }//if return; }//if if (operation != ZREAD) { TupCommitReq * const tupCommitReq = (TupCommitReq *)signal->getDataPtrSend(); Uint32 sig0 = regTcPtr->tupConnectrec; Uint32 tup = refToBlock(regTcPtr->tcTupBlockref); jam(); tupCommitReq->opPtr = sig0; tupCommitReq->gci = regTcPtr->gci; tupCommitReq->hashValue = regTcPtr->hashValue; EXECUTE_DIRECT(tup, GSN_TUP_COMMITREQ, signal, TupCommitReq::SignalLength); }//if Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); signal->theData[0] = regTcPtr->accConnectrec; EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); Uint32 simpleRead = regTcPtr->simpleRead; jamEntry(); if (simpleRead == ZSIMPLE_READ) { jam(); /* ------------------------------------------------------------------------- */ /*THE OPERATION WAS A SIMPLE READ THUS THE COMMIT PHASE IS ONLY NEEDED TO */ /*RELEASE THE LOCKS. AT THIS POINT IN THE CODE THE LOCKS ARE RELEASED AND WE */ /*ARE IN A POSITION TO SEND LQHKEYCONF TO TC. WE WILL ALSO RELEASE ALL */ /*RESOURCES BELONGING TO THIS OPERATION SINCE NO MORE WORK WILL BE */ /*PERFORMED. */ /* ------------------------------------------------------------------------- */ cleanUp(signal); return; }//if }//if Uint32 dirtyOp = regTcPtr->dirtyOp; Uint32 seqNoReplica = regTcPtr->seqNoReplica; if (regTcPtr->gci > regFragptr->newestGci) { jam(); /* ------------------------------------------------------------------------- */ /*IT IS THE FIRST TIME THIS GLOBAL CHECKPOINT IS INVOLVED IN UPDATING THIS */ /*FRAGMENT. UPDATE THE VARIABLE THAT KEEPS TRACK OF NEWEST GCI IN FRAGMENT */ /* ------------------------------------------------------------------------- */ regFragptr->newestGci = regTcPtr->gci; }//if if (dirtyOp != ZTRUE) { if (seqNoReplica != 0) { jam(); completeTransNotLastLab(signal); return; }//if commitReplyLab(signal); return; } else { /* ------------------------------------------------------------------------- */ /*WE MUST HANDLE DIRTY WRITES IN A SPECIAL WAY. THESE OPERATIONS WILL NOT */ /*SEND ANY COMMIT OR COMPLETE MESSAGES TO OTHER NODES. THEY WILL MERELY SEND */ /*THOSE SIGNALS INTERNALLY. */ /* ------------------------------------------------------------------------- */ if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { jam(); packLqhkeyreqLab(signal); } else { ndbrequire(regTcPtr->abortState != TcConnectionrec::NEW_FROM_TC); jam(); sendLqhTransconf(signal, LqhTransConf::Committed); cleanUp(signal); }//if }//if }//Dblqh::commitContinueAfterBlockedLab() void Dblqh::commitReplyLab(Signal* signal) { /* -------------------------------------------------------------- */ /* BACKUP AND STAND-BY REPLICAS ONLY UPDATE THE TRANSACTION STATE */ /* -------------------------------------------------------------- */ TcConnectionrec * const regTcPtr = tcConnectptr.p; TcConnectionrec::AbortState abortState = regTcPtr->abortState; regTcPtr->transactionState = TcConnectionrec::COMMITTED; if (abortState == TcConnectionrec::ABORT_IDLE) { Uint32 clientBlockref = regTcPtr->clientBlockref; if (regTcPtr->seqNoReplica == 0) { jam(); sendCommittedTc(signal, clientBlockref); return; } else { jam(); sendCommitLqh(signal, clientBlockref); return; }//if } else if (regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC) { jam(); signal->theData[0] = regTcPtr->reqRef; signal->theData[1] = cownNodeid; signal->theData[2] = regTcPtr->transid[0]; signal->theData[3] = regTcPtr->transid[1]; sendSignal(tcConnectptr.p->reqBlockref, GSN_COMMITCONF, signal, 4, JBB); } else { ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); jam(); sendLqhTransconf(signal, LqhTransConf::Committed); }//if return; }//Dblqh::commitReplyLab() /* ------------------------------------------------------------------------- */ /* ------- COMPLETE PHASE ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::completeTransNotLastLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { Uint32 clientBlockref = regTcPtr->clientBlockref; jam(); sendCompleteLqh(signal, clientBlockref); cleanUp(signal); return; } else { jam(); completeUnusualLab(signal); return; }//if }//Dblqh::completeTransNotLastLab() void Dblqh::completeTransLastLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { Uint32 clientBlockref = regTcPtr->clientBlockref; jam(); /* ------------------------------------------------------------------------- */ /*DIRTY WRITES WHICH ARE LAST IN THE CHAIN OF REPLICAS WILL SEND COMPLETED */ /*INSTEAD OF SENDING PREPARED TO THE TC (OR OTHER INITIATOR OF OPERATION). */ /* ------------------------------------------------------------------------- */ sendCompletedTc(signal, clientBlockref); cleanUp(signal); return; } else { jam(); completeUnusualLab(signal); return; }//if }//Dblqh::completeTransLastLab() void Dblqh::completeUnusualLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) { jam(); sendAborted(signal); } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); sendLqhTransconf(signal, LqhTransConf::Committed); } else { ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC); jam(); signal->theData[0] = regTcPtr->reqRef; signal->theData[1] = cownNodeid; signal->theData[2] = regTcPtr->transid[0]; signal->theData[3] = regTcPtr->transid[1]; sendSignal(regTcPtr->reqBlockref, GSN_COMPLETECONF, signal, 4, JBB); }//if cleanUp(signal); return; }//Dblqh::completeUnusualLab() /* ========================================================================= */ /* ======= RELEASE TC CONNECT RECORD ======= */ /* */ /* RELEASE A TC CONNECT RECORD TO THE FREELIST. */ /* ========================================================================= */ void Dblqh::releaseTcrec(Signal* signal, TcConnectionrecPtr locTcConnectptr) { jam(); locTcConnectptr.p->tcTimer = 0; locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; locTcConnectptr.p->nextTcConnectrec = cfirstfreeTcConrec; cfirstfreeTcConrec = locTcConnectptr.i; TablerecPtr tabPtr; tabPtr.i = locTcConnectptr.p->tableref; if(tabPtr.i == RNIL) return; ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); /** * Normal case */ ndbrequire(tabPtr.p->usageCount > 0); tabPtr.p->usageCount--; }//Dblqh::releaseTcrec() void Dblqh::releaseTcrecLog(Signal* signal, TcConnectionrecPtr locTcConnectptr) { jam(); locTcConnectptr.p->tcTimer = 0; locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; locTcConnectptr.p->nextTcConnectrec = cfirstfreeTcConrec; cfirstfreeTcConrec = locTcConnectptr.i; TablerecPtr tabPtr; tabPtr.i = locTcConnectptr.p->tableref; if(tabPtr.i == RNIL) return; }//Dblqh::releaseTcrecLog() /* ------------------------------------------------------------------------- */ /* ------- ABORT PHASE ------- */ /* */ /*THIS PART IS USED AT ERRORS THAT CAUSE ABORT OF TRANSACTION. */ /* ------------------------------------------------------------------------- */ /* ***************************************************>> */ /* ABORT: Abort transaction in connection. Sender TC. */ /* This is the normal protocol (See COMMIT) */ /* ***************************************************>> */ void Dblqh::execABORT(Signal* signal) { jamEntry(); Uint32 tcOprec = signal->theData[0]; BlockReference tcBlockref = signal->theData[1]; Uint32 transid1 = signal->theData[2]; Uint32 transid2 = signal->theData[3]; CRASH_INSERTION(5003); if (ERROR_INSERTED(5015)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_ABORT, signal, 2000, 4); return; }//if if (findTransaction(transid1, transid2, tcOprec) != ZOK) { jam(); if(ERROR_INSERTED(5039) && refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ jam(); SET_ERROR_INSERT_VALUE(5040); return; } if(ERROR_INSERTED(5040) && refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ jam(); SET_ERROR_INSERT_VALUE(5003); return; } /* ------------------------------------------------------------------------- */ // SEND ABORTED EVEN IF NOT FOUND. //THE TRANSACTION MIGHT NEVER HAVE ARRIVED HERE. /* ------------------------------------------------------------------------- */ signal->theData[0] = tcOprec; signal->theData[1] = transid1; signal->theData[2] = transid2; signal->theData[3] = cownNodeid; signal->theData[4] = ZTRUE; sendSignal(tcBlockref, GSN_ABORTED, signal, 5, JBB); warningReport(signal, 8); return; }//if /* ------------------------------------------------------------------------- */ /*A GUIDING DESIGN PRINCIPLE IN HANDLING THESE ERROR SITUATIONS HAVE BEEN */ /*KEEP IT SIMPLE. THUS WE RATHER INSERT A WAIT AND SET THE ABORT_STATE TO */ /*ACTIVE RATHER THAN WRITE NEW CODE TO HANDLE EVERY SPECIAL SITUATION. */ /* ------------------------------------------------------------------------- */ TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->nextReplica != ZNIL) { /* ------------------------------------------------------------------------- */ // We will immediately send the ABORT message also to the next LQH node in line. /* ------------------------------------------------------------------------- */ BlockReference TLqhRef = calcLqhBlockRef(regTcPtr->nextReplica); signal->theData[0] = regTcPtr->tcOprec; signal->theData[1] = regTcPtr->tcBlockref; signal->theData[2] = regTcPtr->transid[0]; signal->theData[3] = regTcPtr->transid[1]; sendSignal(TLqhRef, GSN_ABORT, signal, 4, JBB); }//if regTcPtr->abortState = TcConnectionrec::ABORT_FROM_TC; regTcPtr->activeCreat = ZFALSE; const Uint32 commitAckMarker = regTcPtr->commitAckMarker; if(commitAckMarker != RNIL){ jam(); #ifdef MARKER_TRACE { CommitAckMarkerPtr tmp; m_commitAckMarkerHash.getPtr(tmp, commitAckMarker); ndbout_c("Ab2 marker[%.8x %.8x]", tmp.p->transid1, tmp.p->transid2); } #endif m_commitAckMarkerHash.release(commitAckMarker); regTcPtr->commitAckMarker = RNIL; } abortStateHandlerLab(signal); return; }//Dblqh::execABORT() /* ************************************************************************>> * ABORTREQ: Same as ABORT but used in case one node isn't working ok. * (See COMMITREQ) * ************************************************************************>> */ void Dblqh::execABORTREQ(Signal* signal) { jamEntry(); Uint32 reqPtr = signal->theData[0]; BlockReference reqBlockref = signal->theData[1]; Uint32 transid1 = signal->theData[2]; Uint32 transid2 = signal->theData[3]; Uint32 tcOprec = signal->theData[5]; if (ERROR_INSERTED(5006)) { systemErrorLab(signal); } if (ERROR_INSERTED(5016)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_ABORTREQ, signal, 2000, 6); return; }//if if (findTransaction(transid1, transid2, tcOprec) != ZOK) { signal->theData[0] = reqPtr; signal->theData[2] = cownNodeid; signal->theData[3] = transid1; signal->theData[4] = transid2; sendSignal(reqBlockref, GSN_ABORTCONF, signal, 5, JBB); warningReport(signal, 9); return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->transactionState != TcConnectionrec::PREPARED) { warningReport(signal, 10); return; }//if regTcPtr->reqBlockref = reqBlockref; regTcPtr->reqRef = reqPtr; regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; regTcPtr->activeCreat = ZFALSE; abortCommonLab(signal); return; }//Dblqh::execABORTREQ() /* ************>> */ /* ACC_TO_REF > */ /* ************>> */ void Dblqh::execACC_TO_REF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; releaseActiveFrag(signal); abortErrorLab(signal); return; }//Dblqh::execACC_TO_REF() /* ************> */ /* ACCKEYREF > */ /* ************> */ void Dblqh::execACCKEYREF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; terrorCode = signal->theData[1]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); TcConnectionrec * const tcPtr = tcConnectptr.p; switch (tcPtr->transactionState) { case TcConnectionrec::WAIT_ACC: jam(); releaseActiveFrag(signal); break; case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::ABORT_STOPPED: case TcConnectionrec::ABORT_QUEUED: jam(); /* ------------------------------------------------------------------------- */ /*IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ /* ------------------------------------------------------------------------- */ return; break; default: ndbrequire(false); break; }//switch const Uint32 errCode = terrorCode; tcPtr->errorCode = errCode; /* ------------------------------------------------------------------------- */ /*WHEN AN ABORT FROM TC ARRIVES IT COULD ACTUALLY BE A CORRECT BEHAVIOUR */ /*SINCE THE TUPLE MIGHT NOT HAVE ARRIVED YET OR ALREADY HAVE BEEN INSERTED. */ /* ------------------------------------------------------------------------- */ if (tcPtr->activeCreat == ZTRUE) { jam(); /* ------------------------------------------------------------------------- */ /*THIS IS A NORMAL EVENT DURING CREATION OF A FRAGMENT. PERFORM ABORT IN */ /*TUP AND ACC AND THEN CONTINUE WITH NORMAL COMMIT PROCESSING. IF THE ERROR */ /*HAPPENS TO BE A SERIOUS ERROR THEN PERFORM ABORT PROCESSING AS NORMAL. */ /* ------------------------------------------------------------------------- */ switch (tcPtr->operation) { case ZUPDATE: case ZDELETE: jam(); if (errCode != ZNO_TUPLE_FOUND) { jam(); /* ------------------------------------------------------------------------- */ /*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ /*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ /* ------------------------------------------------------------------------- */ tcPtr->activeCreat = ZFALSE; }//if break; case ZINSERT: jam(); if (errCode != ZTUPLE_ALREADY_EXIST) { jam(); /* ------------------------------------------------------------------------- */ /*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ /*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ /* ------------------------------------------------------------------------- */ tcPtr->activeCreat = ZFALSE; }//if break; default: jam(); /* ------------------------------------------------------------------------- */ /*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ /*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ /* ------------------------------------------------------------------------- */ tcPtr->activeCreat = ZFALSE; break; }//switch } else { /** * Only primary replica can get ZTUPLE_ALREADY_EXIST || ZNO_TUPLE_FOUND * * Unless it's a simple or dirty read * * NOT TRUE! * 1) op1 - primary insert ok * 2) op1 - backup insert fail (log full or what ever) * 3) op1 - delete ok @ primary * 4) op1 - delete fail @ backup * * -> ZNO_TUPLE_FOUND is possible */ ndbrequire (tcPtr->seqNoReplica == 0 || errCode != ZTUPLE_ALREADY_EXIST || (tcPtr->operation == ZREAD && (tcPtr->dirtyOp || tcPtr->opSimple))); } tcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; abortCommonLab(signal); return; }//Dblqh::execACCKEYREF() void Dblqh::localAbortStateHandlerLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { jam(); return; }//if regTcPtr->activeCreat = ZFALSE; regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; regTcPtr->errorCode = terrorCode; abortStateHandlerLab(signal); return; }//Dblqh::localAbortStateHandlerLab() void Dblqh::abortStateHandlerLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; switch (regTcPtr->transactionState) { case TcConnectionrec::PREPARED: jam(); /* ------------------------------------------------------------------------- */ /*THE OPERATION IS ALREADY PREPARED AND SENT TO THE NEXT LQH OR BACK TO TC. */ /*WE CAN SIMPLY CONTINUE WITH THE ABORT PROCESS. */ /*IF IT WAS A CHECK FOR TRANSACTION STATUS THEN WE REPORT THE STATUS TO THE */ /*NEW TC AND CONTINUE WITH THE NEXT OPERATION IN LQH. */ /* ------------------------------------------------------------------------- */ if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); sendLqhTransconf(signal, LqhTransConf::Prepared); return; }//if break; case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL: case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: jam(); /* ------------------------------------------------------------------------- */ // We can only reach these states for multi-updates on a record in a transaction. // We know that at least one of those has received the COMMIT signal, thus we // declare us only prepared since we then receive the expected COMMIT signal. /* ------------------------------------------------------------------------- */ ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); sendLqhTransconf(signal, LqhTransConf::Prepared); break; case TcConnectionrec::WAIT_TUPKEYINFO: case TcConnectionrec::WAIT_ATTR: jam(); /* ------------------------------------------------------------------------- */ /* WE ARE CURRENTLY WAITING FOR MORE INFORMATION. WE CAN START THE ABORT */ /* PROCESS IMMEDIATELY. THE KEYINFO AND ATTRINFO SIGNALS WILL BE DROPPED */ /* SINCE THE ABORT STATE WILL BE SET. */ /* ------------------------------------------------------------------------- */ break; case TcConnectionrec::WAIT_TUP: jam(); /* ------------------------------------------------------------------------- */ // TUP is currently active. We have to wait for the TUPKEYREF or TUPKEYCONF // to arrive since we might otherwise jeopardise the local checkpoint // consistency in overload situations. /* ------------------------------------------------------------------------- */ regTcPtr->transactionState = TcConnectionrec::WAIT_TUP_TO_ABORT; return; case TcConnectionrec::WAIT_ACC: jam(); if (regTcPtr->listState == TcConnectionrec::ACC_BLOCK_LIST) { jam(); /* ------------------------------------------------------------------------- */ // If the operation is in the ACC Blocked list the operation is not allowed // to start yet. We release it from the ACC Blocked list and will go through // the gate in abortCommonLab(..) where it will be blocked. /* ------------------------------------------------------------------------- */ fragptr.i = regTcPtr->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); releaseAccList(signal); } else { jam(); /* ------------------------------------------------------------------------- */ // We start the abort immediately since the operation is still in the active // list and the fragment cannot have been frozen yet. By sending LCP_HOLDOPCONF // as direct signals we avoid the problem that we might find the operation // in an unexpected list in ACC. // We cannot accept being blocked before aborting ACC here since that would // lead to seriously complex issues. /* ------------------------------------------------------------------------- */ abortContinueAfterBlockedLab(signal, false); return; }//if break; case TcConnectionrec::LOG_QUEUED: jam(); /* ------------------------------------------------------------------------- */ /*CURRENTLY QUEUED FOR LOGGING. WAIT UNTIL THE LOG RECORD HAVE BEEN INSERTED */ /*AND THEN CONTINUE THE ABORT PROCESS. */ //Could also be waiting for an overloaded log disk. In this case it is easy //to abort when CONTINUEB arrives. /* ------------------------------------------------------------------------- */ return; break; case TcConnectionrec::STOPPED: jam(); /* --------------------------------------------------------------------- * WE ARE CURRENTLY QUEUED FOR ACCESS TO THE FRAGMENT BY A LCP * Since nothing has been done, just release operation * i.e. no prepare log record has been written * so no abort log records needs to be written */ releaseWaitQueue(signal); continueAfterLogAbortWriteLab(signal); return; break; case TcConnectionrec::WAIT_AI_AFTER_ABORT: jam(); /* ------------------------------------------------------------------------- */ /* ABORT OF ACC AND TUP ALREADY COMPLETED. THIS STATE IS ONLY USED WHEN */ /* CREATING A NEW FRAGMENT. */ /* ------------------------------------------------------------------------- */ continueAbortLab(signal); return; break; case TcConnectionrec::WAIT_TUP_TO_ABORT: case TcConnectionrec::ABORT_STOPPED: case TcConnectionrec::LOG_ABORT_QUEUED: case TcConnectionrec::WAIT_ACC_ABORT: case TcConnectionrec::ABORT_QUEUED: jam(); /* ------------------------------------------------------------------------- */ /*ABORT IS ALREADY ONGOING DUE TO SOME ERROR. WE HAVE ALREADY SET THE STATE */ /*OF THE ABORT SO THAT WE KNOW THAT TC EXPECTS A REPORT. WE CAN THUS SIMPLY */ /*EXIT. */ /* ------------------------------------------------------------------------- */ return; break; case TcConnectionrec::COMMIT_STOPPED: case TcConnectionrec::LOG_COMMIT_QUEUED: case TcConnectionrec::COMMIT_QUEUED: jam(); /* ------------------------------------------------------------------------- */ /*THIS IS ONLY AN ALLOWED STATE IF A DIRTY WRITE OR SIMPLE READ IS PERFORMED.*/ /*IF WE ARE MERELY CHECKING THE TRANSACTION STATE IT IS ALSO AN ALLOWED STATE*/ /* ------------------------------------------------------------------------- */ if (regTcPtr->dirtyOp == ZTRUE) { jam(); /* ------------------------------------------------------------------------- */ /*COMPLETE THE DIRTY WRITE AND THEN REPORT COMPLETED BACK TO TC. SINCE IT IS */ /*A DIRTY WRITE IT IS ALLOWED TO COMMIT EVEN IF THE TRANSACTION ABORTS. */ /* ------------------------------------------------------------------------- */ return; }//if if (regTcPtr->simpleRead == ZSIMPLE_READ) { jam(); /* ------------------------------------------------------------------------- */ /*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO */ /*ACC TO CLEAR THE LOCKS. COMPLETE THIS PROCESS AND THEN RETURN AS NORMAL. */ /*NO DATA HAS CHANGED DUE TO THIS SIMPLE READ ANYWAY. */ /* ------------------------------------------------------------------------- */ return; }//if ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); jam(); /* ------------------------------------------------------------------------- */ /*WE ARE ONLY CHECKING THE STATUS OF THE TRANSACTION. IT IS COMMITTING. */ /*COMPLETE THE COMMIT LOCALLY AND THEN SEND REPORT OF COMMITTED TO THE NEW TC*/ /* ------------------------------------------------------------------------- */ return; break; case TcConnectionrec::COMMITTED: jam(); ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); /* ------------------------------------------------------------------------- */ /*WE ARE CHECKING TRANSACTION STATUS. REPORT COMMITTED AND CONTINUE WITH THE */ /*NEXT OPERATION. */ /* ------------------------------------------------------------------------- */ sendLqhTransconf(signal, LqhTransConf::Committed); return; break; default: ndbrequire(false); /* ------------------------------------------------------------------------- */ /*THE STATE WAS NOT AN ALLOWED STATE ON A NORMAL OPERATION. SCANS AND COPY */ /*FRAGMENT OPERATIONS SHOULD HAVE EXECUTED IN ANOTHER PATH. */ /* ------------------------------------------------------------------------- */ break; }//switch abortCommonLab(signal); return; }//Dblqh::abortStateHandlerLab() void Dblqh::abortErrorLab(Signal* signal) { ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { jam(); regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; regTcPtr->errorCode = terrorCode; }//if /* ----------------------------------------------------------------------- * ACTIVE CREATION IS RESET FOR ALL ERRORS WHICH SHOULD BE HANDLED * WITH NORMAL ABORT HANDLING. * ----------------------------------------------------------------------- */ regTcPtr->activeCreat = ZFALSE; abortCommonLab(signal); return; }//Dblqh::abortErrorLab() void Dblqh::abortCommonLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; const Uint32 commitAckMarker = regTcPtr->commitAckMarker; if(regTcPtr->activeCreat != ZTRUE && commitAckMarker != RNIL){ /** * There is no NR ongoing and we have a marker */ jam(); #ifdef MARKER_TRACE { CommitAckMarkerPtr tmp; m_commitAckMarkerHash.getPtr(tmp, commitAckMarker); ndbout_c("Abo marker[%.8x %.8x]", tmp.p->transid1, tmp.p->transid2); } #endif m_commitAckMarkerHash.release(commitAckMarker); regTcPtr->commitAckMarker = RNIL; } fragptr.i = regTcPtr->fragmentptr; if (fragptr.i != RNIL) { jam(); ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: case Fragrecord::CRASH_RECOVERING: case Fragrecord::ACTIVE_CREATION: jam(); linkActiveFrag(signal); abortContinueAfterBlockedLab(signal, true); return; break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); regTcPtr->transactionState = TcConnectionrec::ABORT_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); break; }//switch } else { jam(); continueAbortLab(signal); }//if }//Dblqh::abortCommonLab() void Dblqh::abortContinueAfterBlockedLab(Signal* signal, bool canBlock) { /* ------------------------------------------------------------------------ * INPUT: TC_CONNECTPTR ACTIVE OPERATION RECORD * ------------------------------------------------------------------------ * ------------------------------------------------------------------------ * CAN COME HERE AS RESTART AFTER BEING BLOCKED BY A LOCAL CHECKPOINT. * ------------------------------------------------------------------------ * ALSO AS PART OF A NORMAL ABORT WITHOUT BLOCKING. * WE MUST ABORT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN * AND SEES A STATE IN TUP. * ------------------------------------------------------------------------ */ TcConnectionrec * const regTcPtr = tcConnectptr.p; fragptr.i = regTcPtr->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if ((cCommitBlocked == true) && (fragptr.p->fragActiveStatus == ZTRUE) && (canBlock == true) && (regTcPtr->operation != ZREAD)) { jam(); /* ------------------------------------------------------------------------- */ // TUP and/or ACC have problems in writing the undo log to disk fast enough. // We must avoid the abort at this time and try later instead. The fragment // is also active with a local checkpoint and this commit can generate UNDO // log records that overflow the UNDO log buffer. // // In certain situations it is simply too complex to insert a wait state here // since ACC is active and we cannot release the operation from the active // list without causing great complexity. /* ------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------*/ // We must delay the write of abort info to the log to safe-guard against // a crash due to lack of log pages. We temporary stop all log writes to this // log part to ensure that we don't get a buffer explosion in the delayed // signal buffer instead. /*---------------------------------------------------------------------------*/ releaseActiveFrag(signal); logPartPtr.i = regTcPtr->hashValue & 3; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); linkWaitLog(signal, logPartPtr); regTcPtr->transactionState = TcConnectionrec::ABORT_QUEUED; if (logPartPtr.p->logPartState == LogPartRecord::IDLE) { jam(); logPartPtr.p->logPartState = LogPartRecord::ACTIVE; }//if return; }//if signal->theData[0] = regTcPtr->tupConnectrec; EXECUTE_DIRECT(DBTUP, GSN_TUP_ABORTREQ, signal, 1); regTcPtr->transactionState = TcConnectionrec::WAIT_ACC_ABORT; signal->theData[0] = regTcPtr->accConnectrec; EXECUTE_DIRECT(DBACC, GSN_ACC_ABORTREQ, signal, 1); /* ------------------------------------------------------------------------ * We need to insert a real-time break by sending ACC_ABORTCONF through the * job buffer to ensure that we catch any ACCKEYCONF or TUPKEYCONF or * TUPKEYREF that are in the job buffer but not yet processed. Doing * everything without that would race and create a state error when they * are executed. * ----------------------------------------------------------------------- */ return; }//Dblqh::abortContinueAfterBlockedLab() /* ******************>> */ /* ACC_ABORTCONF > */ /* ******************>> */ void Dblqh::execACC_ABORTCONF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); TcConnectionrec * const regTcPtr = tcConnectptr.p; ndbrequire(regTcPtr->transactionState == TcConnectionrec::WAIT_ACC_ABORT); if (regTcPtr->activeCreat == ZTRUE) { /* ---------------------------------------------------------------------- * A NORMAL EVENT DURING CREATION OF A FRAGMENT. WE NOW NEED TO CONTINUE * WITH NORMAL COMMIT PROCESSING. * ---------------------------------------------------------------------- */ if (regTcPtr->currTupAiLen == regTcPtr->totReclenAi) { jam(); regTcPtr->abortState = TcConnectionrec::ABORT_IDLE; rwConcludedLab(signal); return; } else { ndbrequire(regTcPtr->currTupAiLen < regTcPtr->totReclenAi); jam(); releaseActiveFrag(signal); regTcPtr->transactionState = TcConnectionrec::WAIT_AI_AFTER_ABORT; return; }//if }//if releaseActiveFrag(signal); continueAbortLab(signal); return; }//Dblqh::execACC_ABORTCONF() void Dblqh::continueAbortLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; /* ------------------------------------------------------------------------ * AN ERROR OCCURED IN THE ACTIVE CREATION AFTER THE ABORT PHASE. * WE NEED TO CONTINUE WITH A NORMAL ABORT. * ------------------------------------------------------------------------ * ALSO USED FOR NORMAL CLEAN UP AFTER A NORMAL ABORT. * ------------------------------------------------------------------------ * ALSO USED WHEN NO FRAGMENT WAS SET UP ON OPERATION. * ------------------------------------------------------------------------ */ if (regTcPtr->logWriteState == TcConnectionrec::WRITTEN) { jam(); /* ---------------------------------------------------------------------- * I NEED TO INSERT A ABORT LOG RECORD SINCE WE ARE WRITING LOG IN THIS * TRANSACTION. * ---------------------------------------------------------------------- */ initLogPointers(signal); if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { jam(); /* -------------------------------------------------------------------- * A PREPARE OPERATION IS CURRENTLY WRITING IN THE LOG. * WE MUST WAIT ON OUR TURN TO WRITE THE LOG. * IT IS NECESSARY TO WRITE ONE LOG RECORD COMPLETELY * AT A TIME OTHERWISE WE WILL SCRAMBLE THE LOG. * -------------------------------------------------------------------- */ linkWaitLog(signal, logPartPtr); regTcPtr->transactionState = TcConnectionrec::LOG_ABORT_QUEUED; return; }//if if (cnoOfLogPages == 0) { jam(); /*---------------------------------------------------------------------------*/ // We must delay the write of commit info to the log to safe-guard against // a crash due to lack of log pages. We temporary stop all log writes to this // log part to ensure that we don't get a buffer explosion in the delayed // signal buffer instead. /*---------------------------------------------------------------------------*/ linkWaitLog(signal, logPartPtr); regTcPtr->transactionState = TcConnectionrec::LOG_ABORT_QUEUED; if (logPartPtr.p->logPartState == LogPartRecord::IDLE) { jam(); logPartPtr.p->logPartState = LogPartRecord::ACTIVE; }//if return; }//if writeAbortLog(signal); removeLogTcrec(signal); } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_STARTED) { jam(); } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN) { jam(); /* ------------------------------------------------------------------ * IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG. * ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ * THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE. * THIS CAN OCCUR WHEN WE ARE STARTING A NEW FRAGMENT. * ------------------------------------------------------------------ */ regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; } else { ndbrequire(regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT); jam(); /* ---------------------------------------------------------------- * THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER * A SCAN OF ALL OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT. * THIS INDICATES THAT WE ARE WAITING FOR THIS OPERATION TO COMMIT * OR ABORT SO THAT WE CAN FIND THE * STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT. * ---------------------------------------------------------------- */ checkScanTcCompleted(signal); }//if continueAfterLogAbortWriteLab(signal); return; }//Dblqh::continueAbortLab() void Dblqh::continueAfterLogAbortWriteLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; if (regTcPtr->simpleRead == ZSIMPLE_READ) { jam(); TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); tcKeyRef->connectPtr = regTcPtr->applOprec; tcKeyRef->transId[0] = regTcPtr->transid[0]; tcKeyRef->transId[1] = regTcPtr->transid[1]; tcKeyRef->errorCode = regTcPtr->errorCode; sendSignal(regTcPtr->applRef, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); cleanUp(signal); return; }//if if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_LQH) { LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtrSend(); jam(); lqhKeyRef->userRef = regTcPtr->clientConnectrec; lqhKeyRef->connectPtr = regTcPtr->tcOprec; lqhKeyRef->errorCode = regTcPtr->errorCode; lqhKeyRef->transId1 = regTcPtr->transid[0]; lqhKeyRef->transId2 = regTcPtr->transid[1]; sendSignal(regTcPtr->clientBlockref, GSN_LQHKEYREF, signal, LqhKeyRef::SignalLength, JBB); } else if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) { jam(); sendAborted(signal); } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); sendLqhTransconf(signal, LqhTransConf::Aborted); } else { ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC); jam(); signal->theData[0] = regTcPtr->reqRef; signal->theData[1] = tcConnectptr.i; signal->theData[2] = cownNodeid; signal->theData[3] = regTcPtr->transid[0]; signal->theData[4] = regTcPtr->transid[1]; sendSignal(regTcPtr->reqBlockref, GSN_ABORTCONF, signal, 5, JBB); }//if cleanUp(signal); }//Dblqh::continueAfterLogAbortWriteLab() /* ########################################################################## * ####### MODULE TO HANDLE TC FAILURE ####### * * ########################################################################## */ /* ************************************************************************>> * NODE_FAILREP: Node failure report. Sender Ndbcntr. Set status of failed * node to down and reply with NF_COMPLETEREP to DIH which will report that * LQH has completed failure handling. * ************************************************************************>> */ void Dblqh::execNODE_FAILREP(Signal* signal) { UintR TfoundNodes = 0; UintR TnoOfNodes; UintR Tdata[MAX_NDB_NODES]; Uint32 i; NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0]; TnoOfNodes = nodeFail->noOfNodes; UintR index = 0; for (i = 1; i < MAX_NDB_NODES; i++) { jam(); if(NodeBitmask::get(nodeFail->theNodes, i)){ jam(); Tdata[index] = i; index++; }//if }//for lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); ndbrequire(index == TnoOfNodes); ndbrequire(cnoOfNodes - 1 < MAX_NDB_NODES); for (i = 0; i < TnoOfNodes; i++) { const Uint32 nodeId = Tdata[i]; lcpPtr.p->m_EMPTY_LCP_REQ.clear(nodeId); for (Uint32 j = 0; j < cnoOfNodes; j++) { jam(); if (cnodeData[j] == nodeId){ jam(); cnodeStatus[j] = ZNODE_DOWN; TfoundNodes++; }//if }//for NFCompleteRep * const nfCompRep = (NFCompleteRep *)&signal->theData[0]; nfCompRep->blockNo = DBLQH; nfCompRep->nodeId = cownNodeid; nfCompRep->failedNodeId = Tdata[i]; sendSignal(DBDIH_REF, GSN_NF_COMPLETEREP, signal, NFCompleteRep::SignalLength, JBB); }//for ndbrequire(TnoOfNodes == TfoundNodes); }//Dblqh::execNODE_FAILREP() /* ************************************************************************>> * LQH_TRANSREQ: Report status of all transactions where TC was coordinated * by a crashed TC * ************************************************************************>> */ /* ************************************************************************>> * THIS SIGNAL IS RECEIVED AFTER A NODE CRASH. * THE NODE HAD A TC AND COORDINATED A NUMBER OF TRANSACTIONS. * NOW THE MASTER NODE IS PICKING UP THOSE TRANSACTIONS * TO COMPLETE THEM. EITHER ABORT THEM OR COMMIT THEM. * ************************************************************************>> */ void Dblqh::execLQH_TRANSREQ(Signal* signal) { jamEntry(); Uint32 newTcPtr = signal->theData[0]; BlockReference newTcBlockref = signal->theData[1]; Uint32 oldNodeId = signal->theData[2]; tcNodeFailptr.i = oldNodeId; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); if ((tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_TRUE) || (tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK)) { jam(); tcNodeFailptr.p->lastNewTcBlockref = newTcBlockref; /* ------------------------------------------------------------------------ * WE HAVE RECEIVED A SIGNAL SPECIFYING THAT WE NEED TO HANDLE THE FAILURE * OF A TC. NOW WE RECEIVE ANOTHER SIGNAL WITH THE SAME ORDER. THIS CAN * OCCUR IF THE NEW TC FAILS. WE MUST BE CAREFUL IN THIS CASE SO THAT WE DO * NOT START PARALLEL ACTIVITIES TRYING TO DO THE SAME THING. WE SAVE THE * NEW BLOCK REFERENCE TO THE LAST NEW TC IN A VARIABLE AND ASSIGN TO IT TO * NEW_TC_BLOCKREF WHEN THE OLD PROCESS RETURNS TO LQH_TRANS_NEXT. IT IS * CERTAIN TO COME THERE SINCE THIS IS THE ONLY PATH TO TAKE CARE OF THE * NEXT TC CONNECT RECORD. WE SET THE STATUS TO BREAK TO INDICATE TO THE OLD * PROCESS WHAT IS HAPPENING. * ------------------------------------------------------------------------ */ tcNodeFailptr.p->lastNewTcRef = newTcPtr; tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_BREAK; return; }//if tcNodeFailptr.p->oldNodeId = oldNodeId; tcNodeFailptr.p->newTcBlockref = newTcBlockref; tcNodeFailptr.p->newTcRef = newTcPtr; tcNodeFailptr.p->tcRecNow = 0; tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//Dblqh::execLQH_TRANSREQ() void Dblqh::lqhTransNextLab(Signal* signal) { UintR tend; UintR tstart; UintR guard0; if (tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK) { jam(); /* ---------------------------------------------------------------------- * AN INTERRUPTION TO THIS NODE FAIL HANDLING WAS RECEIVED AND A NEW * TC HAVE BEEN ASSIGNED TO TAKE OVER THE FAILED TC. PROBABLY THE OLD * NEW TC HAVE FAILED. * ---------------------------------------------------------------------- */ tcNodeFailptr.p->newTcBlockref = tcNodeFailptr.p->lastNewTcBlockref; tcNodeFailptr.p->newTcRef = tcNodeFailptr.p->lastNewTcRef; tcNodeFailptr.p->tcRecNow = 0; tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE; }//if tstart = tcNodeFailptr.p->tcRecNow; tend = tstart + 200; guard0 = tend; for (tcConnectptr.i = tstart; tcConnectptr.i <= guard0; tcConnectptr.i++) { jam(); if (tcConnectptr.i >= ctcConnectrecFileSize) { jam(); /** * Finished with scanning operation record * * now scan markers */ scanMarkers(signal, tcNodeFailptr.i, 0, RNIL); return; }//if ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) { if (tcConnectptr.p->transactionState != TcConnectionrec::TC_NOT_CONNECTED) { if (tcConnectptr.p->tcScanRec == RNIL) { if (refToNode(tcConnectptr.p->tcBlockref) == tcNodeFailptr.p->oldNodeId) { if (tcConnectptr.p->operation != ZREAD) { jam(); tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; abortStateHandlerLab(signal); return; } else { jam(); if (tcConnectptr.p->opSimple != ZTRUE) { jam(); tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; abortStateHandlerLab(signal); return; }//if }//if }//if } else { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanType == ScanRecord::COPY) { jam(); if (scanptr.p->scanNodeId == tcNodeFailptr.p->oldNodeId) { jam(); /* ------------------------------------------------------------ * THE RECEIVER OF THE COPY HAVE FAILED. * WE HAVE TO CLOSE THE COPY PROCESS. * ------------------------------------------------------------ */ tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; closeCopyRequestLab(signal); return; }//if } else { if (scanptr.p->scanType == ScanRecord::SCAN) { jam(); if (refToNode(tcConnectptr.p->tcBlockref) == tcNodeFailptr.p->oldNodeId) { jam(); tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; closeScanRequestLab(signal); return; }//if } else { jam(); /* ------------------------------------------------------------ * THIS IS AN ERROR THAT SHOULD NOT OCCUR. WE CRASH THE SYSTEM. * ------------------------------------------------------------ */ systemErrorLab(signal); return; }//if }//if }//if }//if }//if }//for tcNodeFailptr.p->tcRecNow = tend + 1; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//Dblqh::lqhTransNextLab() void Dblqh::scanMarkers(Signal* signal, Uint32 tcNodeFail, Uint32 startBucket, Uint32 i){ jam(); TcNodeFailRecordPtr tcNodeFailPtr; tcNodeFailPtr.i = tcNodeFail; ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord); const Uint32 crashedTcNodeId = tcNodeFailPtr.p->oldNodeId; CommitAckMarkerIterator iter; if(i == RNIL){ m_commitAckMarkerHash.next(startBucket, iter); } else { jam(); iter.curr.i = i; iter.bucket = startBucket; m_commitAckMarkerHash.getPtr(iter.curr); m_commitAckMarkerHash.next(iter); } const Uint32 RT_BREAK = 256; for(i = 0; i<RT_BREAK || iter.bucket == startBucket; i++){ jam(); if(iter.curr.i == RNIL){ /** * Done with iteration */ jam(); tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE; signal->theData[0] = tcNodeFailPtr.p->newTcRef; signal->theData[1] = cownNodeid; signal->theData[2] = LqhTransConf::LastTransConf; sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF, signal, 3, JBB); return; } if(iter.curr.p->tcNodeId == crashedTcNodeId){ jam(); /** * Found marker belonging to crashed node */ LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0]; lqhTransConf->tcRef = tcNodeFailPtr.p->newTcRef; lqhTransConf->lqhNodeId = cownNodeid; lqhTransConf->operationStatus = LqhTransConf::Marker; lqhTransConf->transId1 = iter.curr.p->transid1; lqhTransConf->transId2 = iter.curr.p->transid2; lqhTransConf->apiRef = iter.curr.p->apiRef; lqhTransConf->apiOpRec = iter.curr.p->apiOprec; sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF, signal, 7, JBB); signal->theData[0] = ZSCAN_MARKERS; signal->theData[1] = tcNodeFailPtr.i; signal->theData[2] = iter.bucket; signal->theData[3] = iter.curr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); return; } m_commitAckMarkerHash.next(iter); } signal->theData[0] = ZSCAN_MARKERS; signal->theData[1] = tcNodeFailPtr.i; signal->theData[2] = iter.bucket; signal->theData[3] = RNIL; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); } /* ######################################################################### * ####### SCAN MODULE ####### * * ######################################################################### * ------------------------------------------------------------------------- * THIS MODULE CONTAINS THE CODE THAT HANDLES A SCAN OF A PARTICULAR FRAGMENT * IT OPERATES UNDER THE CONTROL OF TC AND ORDERS ACC TO PERFORM A SCAN OF * ALL TUPLES IN THE FRAGMENT. TUP PERFORMS THE NECESSARY SEARCH CONDITIONS * TO ENSURE THAT ONLY VALID TUPLES ARE RETURNED TO THE APPLICATION. * ------------------------------------------------------------------------- */ void Dblqh::execACC_SCAN_INFO(Signal* signal) { jamEntry(); scanptr.i = signal->theData[0]; c_scanRecordPool.getPtr(scanptr); Uint32 length = signal->theData[3]; ndbrequire(length <= 4); accScanInfoEnterLab(signal, &signal->theData[4], length); }//Dblqh::execACC_SCAN_INFO() void Dblqh::execACC_SCAN_INFO24(Signal* signal) { jamEntry(); scanptr.i = signal->theData[0]; c_scanRecordPool.getPtr(scanptr); Uint32 length = signal->theData[3]; ndbrequire(length <= 20); accScanInfoEnterLab(signal, &signal->theData[4], length); }//Dblqh::execACC_SCAN_INFO24() void Dblqh::accScanInfoEnterLab(Signal* signal, Uint32* dataPtr, Uint32 length) { ndbrequire(length != 0); if (scanptr.p->scanState == ScanRecord::WAIT_SCAN_KEYINFO) { jam(); if (keyinfoLab(signal, dataPtr, length)) { jam(); nextScanConfLoopLab(signal); }//if } else { ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_COPY_KEYINFO); jam(); if (keyinfoLab(signal, dataPtr, length)) { jam(); copySendTupkeyReqLab(signal); }//if }//if }//Dblqh::accScanInfoEnterLab() /* *************** */ /* ACC_SCANCONF > */ /* *************** */ void Dblqh::execACC_SCANCONF(Signal* signal) { AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0]; jamEntry(); scanptr.i = accScanConf->scanPtr; c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanState == ScanRecord::WAIT_ACC_SCAN) { accScanConfScanLab(signal); } else { ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_ACC_COPY); accScanConfCopyLab(signal); }//if }//Dblqh::execACC_SCANCONF() /* ************>> */ /* ACC_SCANREF > */ /* ************>> */ void Dblqh::execACC_SCANREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execACC_SCANREF() /* ***************>> */ /* NEXT_SCANCONF > */ /* ***************>> */ void Dblqh::execNEXT_SCANCONF(Signal* signal) { NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0]; jamEntry(); scanptr.i = nextScanConf->scanPtr; c_scanRecordPool.getPtr(scanptr); if (nextScanConf->localKeyLength == 1) { jam(); nextScanConf->localKey[1] = nextScanConf->localKey[0] & MAX_TUPLES_PER_PAGE; nextScanConf->localKey[0] = nextScanConf->localKey[0] >> MAX_TUPLES_BITS; }//if switch (scanptr.p->scanState) { case ScanRecord::WAIT_CLOSE_SCAN: jam(); accScanCloseConfLab(signal); break; case ScanRecord::WAIT_CLOSE_COPY: jam(); accCopyCloseConfLab(signal); break; case ScanRecord::WAIT_NEXT_SCAN: jam(); nextScanConfScanLab(signal); break; case ScanRecord::WAIT_NEXT_SCAN_COPY: jam(); nextScanConfCopyLab(signal); break; case ScanRecord::WAIT_RELEASE_LOCK: jam(); ndbrequire(signal->length() == 1); scanLockReleasedLab(signal); break; default: ndbrequire(false); }//switch }//Dblqh::execNEXT_SCANCONF() /* ***************> */ /* NEXT_SCANREF > */ /* ***************> */ void Dblqh::execNEXT_SCANREF(Signal* signal) { jamEntry(); systemErrorLab(signal); return; }//Dblqh::execNEXT_SCANREF() /* ******************> */ /* STORED_PROCCONF > */ /* ******************> */ void Dblqh::execSTORED_PROCCONF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; Uint32 storedProcId = signal->theData[1]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); switch (scanptr.p->scanState) { case ScanRecord::WAIT_STORED_PROC_SCAN: jam(); scanptr.p->scanStoredProcId = storedProcId; storedProcConfScanLab(signal); break; case ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN: jam(); releaseActiveFrag(signal); tupScanCloseConfLab(signal); break; case ScanRecord::WAIT_STORED_PROC_COPY: jam(); scanptr.p->scanStoredProcId = storedProcId; storedProcConfCopyLab(signal); break; case ScanRecord::WAIT_DELETE_STORED_PROC_ID_COPY: jam(); releaseActiveFrag(signal); tupCopyCloseConfLab(signal); break; default: ndbrequire(false); }//switch }//Dblqh::execSTORED_PROCCONF() /* ****************** */ /* STORED_PROCREF > */ /* ****************** */ void Dblqh::execSTORED_PROCREF(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; Uint32 errorCode = signal->theData[1]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); switch (scanptr.p->scanState) { case ScanRecord::WAIT_STORED_PROC_SCAN: jam(); scanptr.p->scanStoredProcId = signal->theData[2]; tcConnectptr.p->errorCode = errorCode; closeScanLab(signal); break; default: ndbrequire(false); }//switch }//Dblqh::execSTORED_PROCREF() /* -------------------------------------------------------------------------- * ENTER SCAN_NEXTREQ * -------------------------------------------------------------------------- * PRECONDITION: * TRANSACTION_STATE = SCAN_STATE * SCAN_STATE = WAIT_SCAN_NEXTREQ * * Case scanLockHold: ZTRUE = Unlock previous round of * scanned row(s) and fetch next set of rows. * ZFALSE = Fetch new set of rows. * Number of rows to read depends on parallelism and how many rows * left to scan in the fragment. SCAN_NEXTREQ can also be sent with * closeFlag == ZTRUE to close the scan. * ------------------------------------------------------------------------- */ void Dblqh::execSCAN_NEXTREQ(Signal* signal) { jamEntry(); const ScanFragNextReq * const nextReq = (ScanFragNextReq*)&signal->theData[0]; const Uint32 transid1 = nextReq->transId1; const Uint32 transid2 = nextReq->transId2; const Uint32 senderData = nextReq->senderData; if (findTransaction(transid1, transid2, senderData) != ZOK){ jam(); DEBUG(senderData << " Received SCAN_NEXTREQ in LQH with close flag when closed"); ndbrequire(nextReq->closeFlag == ZTRUE); return; } // Crash node if signal sender is same node CRASH_INSERTION2(5021, refToNode(signal->senderBlockRef()) == cownNodeid); // Crash node if signal sender is NOT same node CRASH_INSERTION2(5022, refToNode(signal->senderBlockRef()) != cownNodeid); if (ERROR_INSERTED(5023)){ // Drop signal if sender is same node if (refToNode(signal->senderBlockRef()) == cownNodeid) { CLEAR_ERROR_INSERT_VALUE; return; } }//if if (ERROR_INSERTED(5024)){ // Drop signal if sender is NOT same node if (refToNode(signal->senderBlockRef()) != cownNodeid) { CLEAR_ERROR_INSERT_VALUE; return; } }//if if (ERROR_INSERTED(5025)){ // Delay signal if sender is NOT same node if (refToNode(signal->senderBlockRef()) != cownNodeid) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_SCAN_NEXTREQ, signal, 1000, signal->length()); return; } }//if if (ERROR_INSERTED(5030)){ ndbout << "ERROR 5030" << endl; CLEAR_ERROR_INSERT_VALUE; // Drop signal return; }//if if(ERROR_INSERTED(5036)){ return; } scanptr.i = tcConnectptr.p->tcScanRec; ndbrequire(scanptr.i != RNIL); c_scanRecordPool.getPtr(scanptr); scanptr.p->scanTcWaiting = ZTRUE; /* ------------------------------------------------------------------ * If close flag is set this scan should be closed * If we are waiting for SCAN_NEXTREQ set flag to stop scanning and * continue execution else set flags and wait until the scan * completes itself * ------------------------------------------------------------------ */ if (nextReq->closeFlag == ZTRUE){ jam(); if(ERROR_INSERTED(5034)){ CLEAR_ERROR_INSERT_VALUE; } if(ERROR_INSERTED(5036)){ CLEAR_ERROR_INSERT_VALUE; return; } closeScanRequestLab(signal); return; }//if fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); /** * Change parameters while running * (is currently not supported) */ const Uint32 max_rows = nextReq->batch_size_rows; const Uint32 max_bytes = nextReq->batch_size_bytes; ndbrequire(scanptr.p->m_max_batch_size_rows == max_rows); ndbrequire(scanptr.p->m_max_batch_size_bytes == max_bytes); /* -------------------------------------------------------------------- * If scanLockHold = TRUE we need to unlock previous round of * scanned records. * scanReleaseLocks will set states for this and send a NEXT_SCANREQ. * When confirm signal NEXT_SCANCONF arrives we call * continueScanNextReqLab to continue scanning new rows and * acquiring new locks. * -------------------------------------------------------------------- */ if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if /* ----------------------------------------------------------------------- * We end up here when scanLockHold = FALSE or no rows was locked from * previous round. * Simply continue scanning. * ----------------------------------------------------------------------- */ continueScanNextReqLab(signal); }//Dblqh::execSCAN_NEXTREQ() void Dblqh::continueScanNextReqLab(Signal* signal) { if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); closeScanLab(signal); return; }//if if(scanptr.p->m_last_row){ jam(); scanptr.p->scanCompletedStatus = ZTRUE; scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); return; } // Update timer on tcConnectRecord tcConnectptr.p->tcTimer = cLqhTimeOutCount; init_acc_ptr_list(scanptr.p); scanptr.p->m_curr_batch_size_rows = 0; scanptr.p->m_curr_batch_size_bytes= 0; scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; scanNextLoopLab(signal); }//Dblqh::continueScanNextReqLab() /* ------------------------------------------------------------------------- * WE NEED TO RELEASE LOCKS BEFORE CONTINUING * ------------------------------------------------------------------------- */ void Dblqh::scanReleaseLocksLab(Signal* signal) { switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_RELEASE_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); }//switch continueScanReleaseAfterBlockedLab(signal); }//Dblqh::scanReleaseLocksLab() void Dblqh::continueScanReleaseAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanState = ScanRecord::WAIT_RELEASE_LOCK; signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1]= get_acc_ptr_from_scan_record(scanptr.p, scanptr.p->scanReleaseCounter -1, false); signal->theData[2] = NextScanReq::ZSCAN_COMMIT; if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); }//Dblqh::continueScanReleaseAfterBlockedLab() /* ------------------------------------------------------------------------- * ENTER SCAN_NEXTREQ * ------------------------------------------------------------------------- * SCAN_NEXT_REQ SIGNAL ARRIVED IN THE MIDDLE OF EXECUTION OF THE SCAN. * IT WAS A REQUEST TO CLOSE THE SCAN. WE WILL CLOSE THE SCAN IN A * CAREFUL MANNER TO ENSURE THAT NO ERROR OCCURS. * ------------------------------------------------------------------------- * PRECONDITION: * TRANSACTION_STATE = SCAN_STATE_USED * TSCAN_COMPLETED = ZTRUE * ------------------------------------------------------------------------- * WE CAN ALSO ARRIVE AT THIS LABEL AFTER A NODE CRASH OF THE SCAN * COORDINATOR. * ------------------------------------------------------------------------- */ void Dblqh::closeScanRequestLab(Signal* signal) { DEBUG("transactionState = " << tcConnectptr.p->transactionState); switch (tcConnectptr.p->transactionState) { case TcConnectionrec::SCAN_STATE_USED: DEBUG("scanState = " << scanptr.p->scanState); switch (scanptr.p->scanState) { case ScanRecord::IN_QUEUE: jam(); tupScanCloseConfLab(signal); break; case ScanRecord::WAIT_SCAN_KEYINFO: case ScanRecord::WAIT_NEXT_SCAN: jam(); /* ------------------------------------------------------------------- * SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN. * ------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; break; case ScanRecord::WAIT_ACC_SCAN: case ScanRecord::WAIT_STORED_PROC_SCAN: jam(); /* ------------------------------------------------------------------- * WE ARE CURRENTLY STARTING UP THE SCAN. SET COMPLETED STATUS * AND WAIT FOR COMPLETION OF STARTUP. * ------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; break; case ScanRecord::WAIT_CLOSE_SCAN: case ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN: jam(); /*empty*/; break; /* ------------------------------------------------------------------- * CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING. * ------------------------------------------------------------------- */ case ScanRecord::WAIT_RELEASE_LOCK: jam(); /* ------------------------------------------------------------------- * WE ARE CURRENTLY RELEASING RECORD LOCKS. AFTER COMPLETING THIS * WE WILL START TO CLOSE THE SCAN. * ------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; break; case ScanRecord::WAIT_SCAN_NEXTREQ: jam(); /* ------------------------------------------------------------------- * WE ARE WAITING FOR A SCAN_NEXTREQ FROM SCAN COORDINATOR(TC) * WICH HAVE CRASHED. CLOSE THE SCAN * ------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (scanptr.p->scanLockHold == ZTRUE) { if (scanptr.p->m_curr_batch_size_rows > 0) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if }//if closeScanLab(signal); break; default: ndbrequire(false); }//switch break; case TcConnectionrec::WAIT_SCAN_AI: jam(); /* --------------------------------------------------------------------- * WE ARE STILL WAITING FOR THE ATTRIBUTE INFORMATION THAT * OBVIOUSLY WILL NOT ARRIVE. WE CAN QUIT IMMEDIATELY HERE. * --------------------------------------------------------------------- */ releaseOprec(signal); if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//if tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; scanptr.p->m_curr_batch_size_rows = 0; scanptr.p->m_curr_batch_size_bytes= 0; sendScanFragConf(signal, ZTRUE); break; case TcConnectionrec::SCAN_TUPKEY: case TcConnectionrec::SCAN_FIRST_STOPPED: case TcConnectionrec::SCAN_CHECK_STOPPED: case TcConnectionrec::SCAN_STOPPED: jam(); /* --------------------------------------------------------------------- * SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN. * --------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; break; case TcConnectionrec::SCAN_RELEASE_STOPPED: jam(); /* --------------------------------------------------------------------- * WE ARE CURRENTLY RELEASING RECORD LOCKS. AFTER COMPLETING * THIS WE WILL START TO CLOSE THE SCAN. * --------------------------------------------------------------------- */ scanptr.p->scanCompletedStatus = ZTRUE; break; case TcConnectionrec::SCAN_CLOSE_STOPPED: jam(); /* --------------------------------------------------------------------- * CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING. * --------------------------------------------------------------------- */ /*empty*/; break; default: ndbrequire(false); }//switch }//Dblqh::closeScanRequestLab() /* ------------------------------------------------------------------------- * ENTER NEXT_SCANCONF * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_RELEASE_LOCK * ------------------------------------------------------------------------- */ void Dblqh::scanLockReleasedLab(Signal* signal) { tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); releaseActiveFrag(signal); if (scanptr.p->scanReleaseCounter == scanptr.p->m_curr_batch_size_rows) { if ((scanptr.p->scanErrorCounter > 0) || (scanptr.p->scanCompletedStatus == ZTRUE)) { jam(); closeScanLab(signal); } else if (scanptr.p->check_scan_batch_completed() && scanptr.p->scanLockHold != ZTRUE) { jam(); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); } else { jam(); /* We came here after releasing locks after receiving SCAN_NEXTREQ from TC. We only come here when scanHoldLock == ZTRUE */ continueScanNextReqLab(signal); }//if } else if (scanptr.p->scanReleaseCounter < scanptr.p->m_curr_batch_size_rows) { jam(); scanptr.p->scanReleaseCounter++; scanReleaseLocksLab(signal); } else { jam(); /* We come here when we have been scanning for a long time and not been able to find m_max_batch_size_rows records to return. We needed to release the record we didn't want, but now we are returning all found records to the API. */ scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); }//if }//Dblqh::scanLockReleasedLab() bool Dblqh::seize_acc_ptr_list(ScanRecord* scanP, Uint32 batch_size) { Uint32 i; Uint32 attr_buf_recs= (batch_size + 30) / 32; if (batch_size > 1) { if (c_no_attrinbuf_recs < attr_buf_recs) { jam(); return false; } for (i= 1; i <= attr_buf_recs; i++) { scanP->scan_acc_op_ptr[i]= seize_attrinbuf(); } } scanP->scan_acc_attr_recs= attr_buf_recs; scanP->scan_acc_index = 0; return true; } void Dblqh::release_acc_ptr_list(ScanRecord* scanP) { Uint32 i, attr_buf_recs; attr_buf_recs= scanP->scan_acc_attr_recs; for (i= 1; i <= attr_buf_recs; i++) { release_attrinbuf(scanP->scan_acc_op_ptr[i]); } scanP->scan_acc_attr_recs= 0; scanP->scan_acc_index = 0; } Uint32 Dblqh::seize_attrinbuf() { AttrbufPtr regAttrPtr; Uint32 ret_attr_buf; ndbrequire(c_no_attrinbuf_recs > 0); c_no_attrinbuf_recs--; ret_attr_buf= cfirstfreeAttrinbuf; regAttrPtr.i= ret_attr_buf; ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); cfirstfreeAttrinbuf= regAttrPtr.p->attrbuf[ZINBUF_NEXT]; return ret_attr_buf; } Uint32 Dblqh::release_attrinbuf(Uint32 attr_buf_i) { Uint32 next_buf; AttrbufPtr regAttrPtr; c_no_attrinbuf_recs++; regAttrPtr.i= attr_buf_i; ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); next_buf= regAttrPtr.p->attrbuf[ZINBUF_NEXT]; regAttrPtr.p->attrbuf[ZINBUF_NEXT]= cfirstfreeAttrinbuf; cfirstfreeAttrinbuf= regAttrPtr.i; return next_buf; } void Dblqh::init_acc_ptr_list(ScanRecord* scanP) { scanP->scan_acc_index = 0; } inline void Dblqh::i_get_acc_ptr(ScanRecord* scanP, Uint32* &acc_ptr, Uint32 index) { if (index == 0) { acc_ptr= (Uint32*)&scanP->scan_acc_op_ptr[0]; } else { Uint32 attr_buf_index, attr_buf_rec; AttrbufPtr regAttrPtr; jam(); attr_buf_rec= (index + 31) / 32; attr_buf_index= (index - 1) & 31; regAttrPtr.i= scanP->scan_acc_op_ptr[attr_buf_rec]; ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); acc_ptr= (Uint32*)®AttrPtr.p->attrbuf[attr_buf_index]; } } Uint32 Dblqh::get_acc_ptr_from_scan_record(ScanRecord* scanP, Uint32 index, bool crash_flag) { Uint32* acc_ptr; Uint32 attr_buf_rec, attr_buf_index; if (!((index < MAX_PARALLEL_OP_PER_SCAN) && index < scanP->scan_acc_index)) { ndbrequire(crash_flag); return RNIL; } i_get_acc_ptr(scanP, acc_ptr, index); return *acc_ptr; } void Dblqh::set_acc_ptr_in_scan_record(ScanRecord* scanP, Uint32 index, Uint32 acc) { Uint32 *acc_ptr; ndbrequire((index == 0 || scanP->scan_acc_index == index) && (index < MAX_PARALLEL_OP_PER_SCAN)); scanP->scan_acc_index= index + 1; i_get_acc_ptr(scanP, acc_ptr, index); *acc_ptr= acc; } /* ------------------------------------------------------------------------- * SCAN_FRAGREQ: Request to start scanning the specified fragment of a table. * ------------------------------------------------------------------------- */ void Dblqh::execSCAN_FRAGREQ(Signal* signal) { ScanFragReq * const scanFragReq = (ScanFragReq *)&signal->theData[0]; ScanFragRef * ref; const Uint32 transid1 = scanFragReq->transId1; const Uint32 transid2 = scanFragReq->transId2; Uint32 errorCode= 0; Uint32 senderData; Uint32 hashIndex; TcConnectionrecPtr nextHashptr; jamEntry(); const Uint32 reqinfo = scanFragReq->requestInfo; const Uint32 fragId = (scanFragReq->fragmentNoKeyLen & 0xFFFF); const Uint32 keyLen = (scanFragReq->fragmentNoKeyLen >> 16); tabptr.i = scanFragReq->tableId; const Uint32 max_rows = scanFragReq->batch_size_rows; const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo); const Uint8 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo); const Uint8 rangeScan = ScanFragReq::getRangeScanFlag(reqinfo); ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); if(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED){ senderData = scanFragReq->senderData; goto error_handler_early_1; } if (cfirstfreeTcConrec != RNIL) { seizeTcrec(); tcConnectptr.p->clientConnectrec = scanFragReq->senderData; tcConnectptr.p->clientBlockref = signal->senderBlockRef(); tcConnectptr.p->savePointId = scanFragReq->savePointId; } else { jam(); /* -------------------------------------------------------------------- * NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST. * -------------------------------------------------------------------- */ errorCode = ZNO_TC_CONNECT_ERROR; senderData = scanFragReq->senderData; goto error_handler_early; }//if /** * A write allways have to get keyinfo */ ndbrequire(scanLockMode == 0 || keyinfo); ndbrequire(max_rows > 0 && max_rows <= MAX_PARALLEL_OP_PER_SCAN); if (!getFragmentrec(signal, fragId)) { errorCode = __LINE__; goto error_handler; }//if // Verify scan type vs table type (both sides are boolean) if (rangeScan != DictTabInfo::isOrderedIndex(fragptr.p->tableType)) { errorCode = __LINE__; // XXX fix goto error_handler; }//if // 1 scan record is reserved for node recovery if (cscanNoFreeRec < 2) { jam(); errorCode = ScanFragRef::ZNO_FREE_SCANREC_ERROR; goto error_handler; } // XXX adjust cmaxAccOps for range scans and remove this comment if ((cbookedAccOps + max_rows) > cmaxAccOps) { jam(); errorCode = ScanFragRef::ZSCAN_BOOK_ACC_OP_ERROR; goto error_handler; }//if ndbrequire(c_scanRecordPool.seize(scanptr)); initScanTc(signal, transid1, transid2, fragId, ZNIL); tcConnectptr.p->save1 = 4; tcConnectptr.p->primKeyLen = keyLen + 4; // hard coded in execKEYINFO errorCode = initScanrec(scanFragReq); if (errorCode != ZOK) { jam(); goto error_handler2; }//if cscanNoFreeRec--; cbookedAccOps += max_rows; hashIndex = (tcConnectptr.p->transid[0] ^ tcConnectptr.p->tcOprec) & 1023; nextHashptr.i = ctransidHash[hashIndex]; ctransidHash[hashIndex] = tcConnectptr.i; tcConnectptr.p->prevHashRec = RNIL; tcConnectptr.p->nextHashRec = nextHashptr.i; if (nextHashptr.i != RNIL) { jam(); /* --------------------------------------------------------------------- * ENSURE THAT THE NEXT RECORD HAS SET PREVIOUS TO OUR RECORD * IF IT EXISTS * --------------------------------------------------------------------- */ ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec); nextHashptr.p->prevHashRec = tcConnectptr.i; }//if if (scanptr.p->scanAiLength > 0) { jam(); tcConnectptr.p->transactionState = TcConnectionrec::WAIT_SCAN_AI; return; }//if continueAfterReceivingAllAiLab(signal); return; error_handler2: // no scan number allocated c_scanRecordPool.release(scanptr); error_handler: ref = (ScanFragRef*)&signal->theData[0]; tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; ref->senderData = tcConnectptr.p->clientConnectrec; ref->transId1 = transid1; ref->transId2 = transid2; ref->errorCode = errorCode; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); return; error_handler_early_1: if(tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ jam(); errorCode = ZTABLE_NOT_DEFINED; } else if (tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ jam(); errorCode = ZDROP_TABLE_IN_PROGRESS; } else { ndbrequire(0); } error_handler_early: ref = (ScanFragRef*)&signal->theData[0]; ref->senderData = senderData; ref->transId1 = transid1; ref->transId2 = transid2; ref->errorCode = errorCode; sendSignal(signal->senderBlockRef(), GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); }//Dblqh::execSCAN_FRAGREQ() void Dblqh::continueAfterReceivingAllAiLab(Signal* signal) { tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ jam(); return; } scanptr.p->scanState = ScanRecord::WAIT_ACC_SCAN; AccScanReq * req = (AccScanReq*)&signal->theData[0]; req->senderData = scanptr.i; req->senderRef = cownref; req->tableId = tcConnectptr.p->tableref; req->fragmentNo = tcConnectptr.p->fragmentid; req->requestInfo = 0; AccScanReq::setLockMode(req->requestInfo, scanptr.p->scanLockMode); AccScanReq::setKeyinfoFlag(req->requestInfo, scanptr.p->scanKeyinfoFlag); AccScanReq::setReadCommittedFlag(req->requestInfo, scanptr.p->readCommitted); req->transId1 = tcConnectptr.p->transid[0]; req->transId2 = tcConnectptr.p->transid[1]; req->savePointId = tcConnectptr.p->savePointId; // always use if-stmt to switch (instead of setting a "scan block ref") if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_SCANREQ, signal, AccScanReq::SignalLength, JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_ACC_SCANREQ, signal, AccScanReq::SignalLength, JBB); }//Dblqh::continueAfterReceivingAllAiLab() void Dblqh::scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { if (tcConnectptr.p->currTupAiLen < scanptr.p->scanAiLength) { jam(); } else { jam(); ndbrequire(tcConnectptr.p->currTupAiLen == scanptr.p->scanAiLength); continueAfterReceivingAllAiLab(signal); }//if return; }//if terrorCode = ZGET_ATTRINBUF_ERROR; finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->transactionState = TcConnectionrec::IDLE; tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; ScanFragRef * ref = (ScanFragRef*)&signal->theData[0]; ref->senderData = tcConnectptr.p->clientConnectrec; ref->transId1 = tcConnectptr.p->transid[0]; ref->transId2 = tcConnectptr.p->transid[1]; ref->errorCode = terrorCode; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); deleteTransidHash(signal); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); }//Dblqh::scanAttrinfoLab() /*---------------------------------------------------------------------*/ /* Send this 'I am alive' signal to TC when it is received from ACC */ /* We include the scanPtr.i that comes from ACC in signalData[1], this */ /* tells TC which fragment record to check for a timeout. */ /*---------------------------------------------------------------------*/ void Dblqh::execSCAN_HBREP(Signal* signal) { jamEntry(); scanptr.i = signal->theData[0]; c_scanRecordPool.getPtr(scanptr); switch(scanptr.p->scanType){ case ScanRecord::SCAN: if (scanptr.p->scanTcWaiting == ZTRUE) { jam(); tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); const Uint32 transid1 = signal->theData[1]; const Uint32 transid2 = signal->theData[2]; ndbrequire(transid1 == tcConnectptr.p->transid[0] && transid2 == tcConnectptr.p->transid[1]); // Update counter on tcConnectPtr if (tcConnectptr.p->tcTimer != 0){ tcConnectptr.p->tcTimer = cLqhTimeOutCount; } else { jam(); //ndbout << "SCAN_HBREP when tcTimer was off" << endl; } signal->theData[0] = tcConnectptr.p->clientConnectrec; signal->theData[1] = tcConnectptr.p->transid[0]; signal->theData[2] = tcConnectptr.p->transid[1]; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_HBREP, signal, 3, JBB); }//if break; case ScanRecord::COPY: // ndbout << "Dblqh::execSCAN_HBREP Dropping SCAN_HBREP" << endl; break; default: ndbrequire(false); } } void Dblqh::sendScanFragRefLateLab(Signal* signal) { }//Dblqh::sendScanFragRefLateLab() void Dblqh::accScanConfScanLab(Signal* signal) { AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0]; tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); /* ----------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_ACC_SCAN * ----------------------------------------------------------------------- */ if (accScanConf->flag == AccScanConf::ZEMPTY_FRAGMENT) { jam(); /* --------------------------------------------------------------------- * THE FRAGMENT WAS EMPTY. * REPORT SUCCESSFUL COPYING. * --------------------------------------------------------------------- */ tupScanCloseConfLab(signal); return; }//if scanptr.p->scanAccPtr = accScanConf->accPtr; Uint32 boundAiLength = tcConnectptr.p->primKeyLen - 4; if (scanptr.p->rangeScan) { jam(); TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend(); req->errorCode = RNIL; req->tuxScanPtrI = scanptr.p->scanAccPtr; req->boundAiLength = boundAiLength; if(boundAiLength > 0) sendKeyinfoAcc(signal, TuxBoundInfo::SignalLength); EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO, signal, TuxBoundInfo::SignalLength + boundAiLength); jamEntry(); if (req->errorCode != 0) { jam(); /* * Cannot use STORED_PROCREF to abort since even the REF * returns a stored proc id. So record error and continue. * The scan is already Invalid in TUX and returns empty set. */ tcConnectptr.p->errorCode = req->errorCode; } } scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_SCAN; signal->theData[0] = tcConnectptr.p->tupConnectrec; signal->theData[1] = tcConnectptr.p->tableref; signal->theData[2] = scanptr.p->scanSchemaVersion; signal->theData[3] = ZSTORED_PROC_SCAN; signal->theData[4] = scanptr.p->scanAiLength; sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); signal->theData[0] = tcConnectptr.p->tupConnectrec; AttrbufPtr regAttrinbufptr; regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf; while (regAttrinbufptr.i != RNIL) { ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); jam(); Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; ndbrequire(dataLen != 0); // first 3 words already set in STORED_PROCREQ MEMCOPY_NO_WORDS(&signal->theData[3], ®Attrinbufptr.p->attrbuf[0], dataLen); sendSignal(tcConnectptr.p->tcTupBlockref, GSN_ATTRINFO, signal, dataLen + 3, JBB); regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; }//while releaseOprec(signal); }//Dblqh::accScanConfScanLab() /* ------------------------------------------------------------------------- * ENTER STORED_PROCCONF WITH * TC_CONNECTPTR, * TSTORED_PROC_ID * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_STORED_PROC_SCAN * ------------------------------------------------------------------------- */ void Dblqh::storedProcConfScanLab(Signal* signal) { fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); // STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. closeScanLab(signal); return; }//if switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_FIRST_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); break; }//switch continueFirstScanAfterBlockedLab(signal); }//Dblqh::storedProcConfScanLab() void Dblqh::continueFirstScanAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN; init_acc_ptr_list(scanptr.p); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = RNIL; signal->theData[2] = NextScanReq::ZSCAN_NEXT; if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); return; }//Dblqh::continueFirstScanAfterBlockedLab() /* ------------------------------------------------------------------------- * When executing a scan we must come up to the surface at times to make * sure we can quickly start local checkpoints. * ------------------------------------------------------------------------- */ void Dblqh::execCHECK_LCP_STOP(Signal* signal) { jamEntry(); scanptr.i = signal->theData[0]; c_scanRecordPool.getPtr(scanptr); tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (signal->theData[1] == ZTRUE) { jam(); releaseActiveFrag(signal); signal->theData[0] = ZCHECK_LCP_STOP_BLOCKED; signal->theData[1] = scanptr.i; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); signal->theData[0] = RNIL; return; }//if if (fragptr.p->fragStatus != Fragrecord::FSACTIVE) { ndbrequire(fragptr.p->fragStatus == Fragrecord::BLOCKED); releaseActiveFrag(signal); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_CHECK_STOPPED; signal->theData[0] = RNIL; }//if }//Dblqh::execCHECK_LCP_STOP() void Dblqh::checkLcpStopBlockedLab(Signal* signal) { switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); continueAfterCheckLcpStopBlocked(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_CHECK_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); }//switch }//Dblqh::checkLcpStopBlockedLab() void Dblqh::continueAfterCheckLcpStopBlocked(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = AccCheckScan::ZNOT_CHECK_LCP_STOP; if (! scanptr.p->rangeScan) EXECUTE_DIRECT(DBACC, GSN_ACC_CHECK_SCAN, signal, 2); else EXECUTE_DIRECT(DBTUX, GSN_ACC_CHECK_SCAN, signal, 2); }//Dblqh::continueAfterCheckLcpStopBlocked() /* ------------------------------------------------------------------------- * ENTER NEXT_SCANCONF * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_NEXT_SCAN * ------------------------------------------------------------------------- */ void Dblqh::nextScanConfScanLab(Signal* signal) { NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0]; tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); if (nextScanConf->fragId == RNIL) { jam(); /* --------------------------------------------------------------------- * THERE ARE NO MORE TUPLES TO FETCH. IF WE HAVE ANY * OPERATIONS STILL NEEDING A LOCK WE REPORT TO THE * APPLICATION AND CLOSE THE SCAN WHEN THE NEXT SCAN * REQUEST IS RECEIVED. IF WE DO NOT HAVE ANY NEED FOR * LOCKS WE CAN CLOSE THE SCAN IMMEDIATELY. * --------------------------------------------------------------------- */ releaseActiveFrag(signal); /************************************************************* * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. ************************************************************ */ if (scanptr.p->scanCompletedStatus == ZTRUE) { if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->m_curr_batch_size_rows > 0) { jam(); scanptr.p->scanCompletedStatus = ZTRUE; scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); return; }//if closeScanLab(signal); return; }//if // If accOperationPtr == RNIL no record was returned by ACC if (nextScanConf->accOperationPtr == RNIL) { jam(); /************************************************************* * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. ************************************************************ */ if (scanptr.p->scanCompletedStatus == ZTRUE) { releaseActiveFrag(signal); if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->m_curr_batch_size_rows > 0) { jam(); releaseActiveFrag(signal); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); return; }//if signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP; if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB); return; }//if jam(); set_acc_ptr_in_scan_record(scanptr.p, scanptr.p->m_curr_batch_size_rows, nextScanConf->accOperationPtr); jam(); scanptr.p->scanLocalref[0] = nextScanConf->localKey[0]; scanptr.p->scanLocalref[1] = nextScanConf->localKey[1]; scanptr.p->scanLocalFragid = nextScanConf->fragId; if (scanptr.p->scanKeyinfoFlag) { jam(); tcConnectptr.p->primKeyLen = nextScanConf->keyLength; seizeTupkeybuf(signal); databufptr.p->data[0] = nextScanConf->key[0]; databufptr.p->data[1] = nextScanConf->key[1]; databufptr.p->data[2] = nextScanConf->key[2]; databufptr.p->data[3] = nextScanConf->key[3]; if (nextScanConf->keyLength > 4) { jam(); tcConnectptr.p->save1 = 4; scanptr.p->scanState = ScanRecord::WAIT_SCAN_KEYINFO; return; }//if }//if jam(); nextScanConfLoopLab(signal); }//Dblqh::nextScanConfScanLab() void Dblqh::nextScanConfLoopLab(Signal* signal) { /* ---------------------------------------------------------------------- * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. * ---------------------------------------------------------------------- */ if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); releaseActiveFrag(signal); releaseOprec(signal); if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if closeScanLab(signal); return; }//if jam(); Uint32 tableRef; Uint32 tupFragPtr; Uint32 reqinfo = (scanptr.p->scanLockHold == ZFALSE); reqinfo = reqinfo + (tcConnectptr.p->operation << 6); reqinfo = reqinfo + (tcConnectptr.p->opExec << 10); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_TUPKEY; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (! scanptr.p->rangeScan) { tableRef = tcConnectptr.p->tableref; if (fragptr.p->fragId == scanptr.p->scanLocalFragid) { jam(); tupFragPtr = fragptr.p->tupFragptr[0]; } else { jam(); tupFragPtr = fragptr.p->tupFragptr[1]; }//if } else { jam(); // for ordered index use primary table FragrecordPtr tFragPtr; tFragPtr.i = fragptr.p->tableFragptr; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); tableRef = tFragPtr.p->tabRef; if (tFragPtr.p->fragId == scanptr.p->scanLocalFragid) { jam(); tupFragPtr = tFragPtr.p->tupFragptr[0]; } else { jam(); tupFragPtr = tFragPtr.p->tupFragptr[1]; }//if } { jam(); TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); tupKeyReq->connectPtr = tcConnectptr.p->tupConnectrec; tupKeyReq->request = reqinfo; tupKeyReq->tableRef = tableRef; tupKeyReq->fragId = scanptr.p->scanLocalFragid; tupKeyReq->keyRef1 = scanptr.p->scanLocalref[0]; tupKeyReq->keyRef2 = scanptr.p->scanLocalref[1]; tupKeyReq->attrBufLen = 0; tupKeyReq->opRef = scanptr.p->scanApiOpPtr; tupKeyReq->applRef = scanptr.p->scanApiBlockref; tupKeyReq->schemaVersion = scanptr.p->scanSchemaVersion; tupKeyReq->storedProcedure = scanptr.p->scanStoredProcId; tupKeyReq->transId1 = tcConnectptr.p->transid[0]; tupKeyReq->transId2 = tcConnectptr.p->transid[1]; tupKeyReq->fragPtr = tupFragPtr; tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; tupKeyReq->savePointId = tcConnectptr.p->savePointId; Uint32 blockNo = refToBlock(tcConnectptr.p->tcTupBlockref); EXECUTE_DIRECT(blockNo, GSN_TUPKEYREQ, signal, TupKeyReq::SignalLength); } } /* ------------------------------------------------------------------------- * RECEPTION OF FURTHER KEY INFORMATION WHEN KEY SIZE > 16 BYTES. * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_SCAN_KEYINFO * ------------------------------------------------------------------------- */ bool Dblqh::keyinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) { tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); Uint32 index = 0; do { jam(); seizeTupkeybuf(signal); databufptr.p->data[0] = dataPtr[index]; databufptr.p->data[1] = dataPtr[index + 1]; databufptr.p->data[2] = dataPtr[index + 2]; databufptr.p->data[3] = dataPtr[index + 3]; index += 4; tcConnectptr.p->save1 = tcConnectptr.p->save1 + 4; if (tcConnectptr.p->save1 >= tcConnectptr.p->primKeyLen) { jam(); return true; }//if if (index >= length) { jam(); return false; }//if } while (index < 20); ndbrequire(false); return false; }//Dblqh::keyinfoLab() /* ------------------------------------------------------------------------- * ENTER TUPKEYCONF * ------------------------------------------------------------------------- * PRECONDITION: TRANSACTION_STATE = SCAN_TUPKEY * ------------------------------------------------------------------------- */ void Dblqh::scanTupkeyConfLab(Signal* signal) { const TupKeyConf * conf = (TupKeyConf *)signal->getDataPtr(); UintR tdata4 = conf->readLength; UintR tdata5 = conf->lastRow; tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; scanptr.i = tcConnectptr.p->tcScanRec; releaseActiveFrag(signal); c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanCompletedStatus == ZTRUE) { /* --------------------------------------------------------------------- * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. * --------------------------------------------------------------------- */ releaseOprec(signal); if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->scanKeyinfoFlag) { jam(); sendKeyinfo20(signal, scanptr.p, tcConnectptr.p); releaseOprec(signal); tdata4 += tcConnectptr.p->primKeyLen;// Inform API about keyinfo len aswell }//if ndbrequire(scanptr.p->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN); scanptr.p->m_curr_batch_size_bytes+= tdata4; scanptr.p->m_curr_batch_size_rows++; scanptr.p->m_last_row = tdata5; if (scanptr.p->check_scan_batch_completed() | tdata5){ if (scanptr.p->scanLockHold == ZTRUE) { jam(); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); return; } else { jam(); scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows; scanReleaseLocksLab(signal); return; } } else { if (scanptr.p->scanLockHold == ZTRUE) { jam(); scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; } else { jam(); scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT; } } scanNextLoopLab(signal); }//Dblqh::scanTupkeyConfLab() void Dblqh::scanNextLoopLab(Signal* signal) { switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); }//switch continueScanAfterBlockedLab(signal); }//Dblqh::scanNextLoopLab() void Dblqh::continueScanAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); Uint32 accOpPtr; if (scanptr.p->scanFlag == NextScanReq::ZSCAN_NEXT_ABORT) { jam(); scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT; accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, scanptr.p->m_curr_batch_size_rows, false); scanptr.p->scan_acc_index--; } else if (scanptr.p->scanFlag == NextScanReq::ZSCAN_NEXT_COMMIT) { jam(); accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, scanptr.p->m_curr_batch_size_rows-1, false); } else { jam(); accOpPtr = RNIL; // The value is not used in ACC }//if scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN; signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = accOpPtr; signal->theData[2] = scanptr.p->scanFlag; if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3,JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3,JBB); }//Dblqh::continueScanAfterBlockedLab() /* ------------------------------------------------------------------------- * ENTER TUPKEYREF WITH * TC_CONNECTPTR, * TERROR_CODE * ------------------------------------------------------------------------- * PRECONDITION: TRANSACTION_STATE = SCAN_TUPKEY * ------------------------------------------------------------------------- */ void Dblqh::scanTupkeyRefLab(Signal* signal) { tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; scanptr.i = tcConnectptr.p->tcScanRec; releaseActiveFrag(signal); releaseOprec(signal); c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanCompletedStatus == ZTRUE) { /* --------------------------------------------------------------------- * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. * --------------------------------------------------------------------- */ if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if ((terrorCode != ZSEARCH_CONDITION_FALSE) && (terrorCode != ZNO_TUPLE_FOUND) && (terrorCode >= ZUSER_ERROR_CODE_LIMIT)) { scanptr.p->scanErrorCounter++; tcConnectptr.p->errorCode = terrorCode; if (scanptr.p->scanLockHold == ZTRUE) { jam(); scanptr.p->scanReleaseCounter = 1; } else { jam(); scanptr.p->m_curr_batch_size_rows++; scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows; }//if /* -------------------------------------------------------------------- * WE NEED TO RELEASE ALL LOCKS CURRENTLY * HELD BY THIS SCAN. * -------------------------------------------------------------------- */ scanReleaseLocksLab(signal); return; }//if Uint32 time_passed= tcConnectptr.p->tcTimer - cLqhTimeOutCount; if (scanptr.p->m_curr_batch_size_rows > 0) { if (time_passed > 1) { /* ----------------------------------------------------------------------- * WE NEED TO ENSURE THAT WE DO NOT SEARCH FOR THE NEXT TUPLE FOR A * LONG TIME WHILE WE KEEP A LOCK ON A FOUND TUPLE. WE RATHER REPORT * THE FOUND TUPLE IF FOUND TUPLES ARE RARE. If more than 10 ms passed we * send the found tuples to the API. * ----------------------------------------------------------------------- */ scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows + 1; scanReleaseLocksLab(signal); return; } } else { if (time_passed > 10) { jam(); signal->theData[0]= scanptr.i; signal->theData[1]= tcConnectptr.p->transid[0]; signal->theData[2]= tcConnectptr.p->transid[1]; execSCAN_HBREP(signal); } } scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_ABORT; scanNextLoopLab(signal); }//Dblqh::scanTupkeyRefLab() /* ------------------------------------------------------------------------- * THE SCAN HAS BEEN COMPLETED. EITHER BY REACHING THE END OR BY COMMAND * FROM THE APPLICATION OR BY SOME SORT OF ERROR CONDITION. * ------------------------------------------------------------------------- */ void Dblqh::closeScanLab(Signal* signal) { fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::SCAN_CLOSE_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: ndbrequire(false); }//switch continueCloseScanAfterBlockedLab(signal); }//Dblqh::closeScanLab() void Dblqh::continueCloseScanAfterBlockedLab(Signal* signal) { tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanState = ScanRecord::WAIT_CLOSE_SCAN; signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = RNIL; signal->theData[2] = NextScanReq::ZSCAN_CLOSE; if (! scanptr.p->rangeScan) sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); else sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); }//Dblqh::continueCloseScanAfterBlockedLab() /* ------------------------------------------------------------------------- * ENTER NEXT_SCANCONF * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_CLOSE_SCAN * ------------------------------------------------------------------------- */ void Dblqh::accScanCloseConfLab(Signal* signal) { tcConnectptr.i = scanptr.p->scanTcrec; scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); signal->theData[0] = tcConnectptr.p->tupConnectrec; signal->theData[1] = tcConnectptr.p->tableref; signal->theData[2] = scanptr.p->scanSchemaVersion; signal->theData[3] = ZDELETE_STORED_PROC_ID; signal->theData[4] = scanptr.p->scanStoredProcId; sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); }//Dblqh::accScanCloseConfLab() /* ------------------------------------------------------------------------- * ENTER STORED_PROCCONF WITH * ------------------------------------------------------------------------- * PRECONDITION: SCAN_STATE = WAIT_DELETE_STORED_PROC_ID_SCAN * ------------------------------------------------------------------------- */ void Dblqh::tupScanCloseConfLab(Signal* signal) { fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); } else if (tcConnectptr.p->errorCode != 0) { jam(); ScanFragRef * ref = (ScanFragRef*)&signal->theData[0]; ref->senderData = tcConnectptr.p->clientConnectrec; ref->transId1 = tcConnectptr.p->transid[0]; ref->transId2 = tcConnectptr.p->transid[1]; ref->errorCode = tcConnectptr.p->errorCode; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); } else { jam(); scanptr.p->m_curr_batch_size_rows = 0; scanptr.p->m_curr_batch_size_bytes= 0; sendScanFragConf(signal, ZSCAN_FRAG_CLOSED); }//if finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->tcScanRec = RNIL; deleteTransidHash(signal); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); }//Dblqh::tupScanCloseConfLab() /* ========================================================================= * ======= INITIATE SCAN RECORD ======= * * SUBROUTINE SHORT NAME = ISC * ========================================================================= */ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) { const Uint32 reqinfo = scanFragReq->requestInfo; const Uint32 max_rows = scanFragReq->batch_size_rows; const Uint32 max_bytes = scanFragReq->batch_size_bytes; const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo); const Uint32 scanLockHold = ScanFragReq::getHoldLockFlag(reqinfo); const Uint32 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo); const Uint32 readCommitted = ScanFragReq::getReadCommittedFlag(reqinfo); const Uint32 idx = ScanFragReq::getRangeScanFlag(reqinfo); const Uint32 attrLen = ScanFragReq::getAttrLen(reqinfo); const Uint32 scanPrio = ScanFragReq::getScanPrio(reqinfo); scanptr.p->scanKeyinfoFlag = keyinfo; scanptr.p->scanLockHold = scanLockHold; scanptr.p->scanCompletedStatus = ZFALSE; scanptr.p->scanType = ScanRecord::SCAN; scanptr.p->scanApiBlockref = scanFragReq->resultRef; scanptr.p->scanAiLength = attrLen; scanptr.p->scanTcrec = tcConnectptr.i; scanptr.p->scanSchemaVersion = scanFragReq->schemaVersion; scanptr.p->m_curr_batch_size_rows = 0; scanptr.p->m_curr_batch_size_bytes= 0; scanptr.p->m_max_batch_size_rows = max_rows; scanptr.p->m_max_batch_size_bytes = max_bytes; scanptr.p->scanErrorCounter = 0; scanptr.p->scanLockMode = scanLockMode; scanptr.p->readCommitted = readCommitted; scanptr.p->rangeScan = idx; scanptr.p->scanState = ScanRecord::SCAN_FREE; scanptr.p->scanFlag = ZFALSE; scanptr.p->scanLocalref[0] = 0; scanptr.p->scanLocalref[1] = 0; scanptr.p->scanLocalFragid = 0; scanptr.p->scanTcWaiting = ZTRUE; scanptr.p->scanNumber = ~0; scanptr.p->scanApiOpPtr = scanFragReq->clientOpPtr; scanptr.p->m_last_row = 0; if (max_rows == 0 || (max_bytes > 0 && max_rows > max_bytes)){ jam(); return ScanFragRef::ZWRONG_BATCH_SIZE; } if (!seize_acc_ptr_list(scanptr.p, max_rows)){ jam(); return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; } /** * Used for scan take over */ FragrecordPtr tFragPtr; tFragPtr.i = fragptr.p->tableFragptr; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); scanptr.p->fragPtrI = fragptr.p->tableFragptr; /** * !idx uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) = 1-11 * idx uses from MAX_PARALLEL_SCANS_PER_FRAG - MAX = 12-42) */ Uint32 start = (idx ? MAX_PARALLEL_SCANS_PER_FRAG : 1 ); Uint32 stop = (idx ? MAX_PARALLEL_INDEX_SCANS_PER_FRAG : MAX_PARALLEL_SCANS_PER_FRAG - 1); stop += start; Uint32 free = tFragPtr.p->m_scanNumberMask.find(start); if(free == Fragrecord::ScanNumberMask::NotFound || free >= stop){ jam(); if(scanPrio == 0){ jam(); return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; } /** * Put on queue */ scanptr.p->scanState = ScanRecord::IN_QUEUE; LocalDLFifoList<ScanRecord> queue(c_scanRecordPool, tFragPtr.p->m_queuedScans); queue.add(scanptr); return ZOK; } scanptr.p->scanNumber = free; tFragPtr.p->m_scanNumberMask.clear(free);// Update mask LocalDLList<ScanRecord> active(c_scanRecordPool, tFragPtr.p->m_activeScans); active.add(scanptr); if(scanptr.p->scanKeyinfoFlag){ jam(); #ifdef VM_TRACE ScanRecordPtr tmp; ndbrequire(!c_scanTakeOverHash.find(tmp, * scanptr.p)); #endif #ifdef TRACE_SCAN_TAKEOVER ndbout_c("adding (%d %d) table: %d fragId: %d frag.i: %d tableFragptr: %d", scanptr.p->scanNumber, scanptr.p->fragPtrI, tabptr.i, scanFragReq->fragmentNo, fragptr.i, fragptr.p->tableFragptr); #endif c_scanTakeOverHash.add(scanptr); } init_acc_ptr_list(scanptr.p); return ZOK; } /* ========================================================================= * ======= INITIATE TC RECORD AT SCAN ======= * * SUBROUTINE SHORT NAME = IST * ========================================================================= */ void Dblqh::initScanTc(Signal* signal, Uint32 transid1, Uint32 transid2, Uint32 fragId, Uint32 nodeId) { tcConnectptr.p->transid[0] = transid1; tcConnectptr.p->transid[1] = transid2; tcConnectptr.p->tcScanRec = scanptr.i; tcConnectptr.p->tableref = tabptr.i; tcConnectptr.p->fragmentid = fragId; tcConnectptr.p->fragmentptr = fragptr.i; tcConnectptr.p->tcOprec = tcConnectptr.p->clientConnectrec; tcConnectptr.p->tcBlockref = tcConnectptr.p->clientBlockref; tcConnectptr.p->errorCode = 0; tcConnectptr.p->reclenAiLqhkey = 0; tcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; tcConnectptr.p->nextReplica = nodeId; tcConnectptr.p->currTupAiLen = 0; tcConnectptr.p->opExec = 1; tcConnectptr.p->operation = ZREAD; tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; tcConnectptr.p->commitAckMarker = RNIL; tabptr.p->usageCount++; }//Dblqh::initScanTc() /* ========================================================================= * ======= FINISH SCAN RECORD ======= * * REMOVE SCAN RECORD FROM PER FRAGMENT LIST. * ========================================================================= */ void Dblqh::finishScanrec(Signal* signal) { release_acc_ptr_list(scanptr.p); FragrecordPtr tFragPtr; tFragPtr.i = scanptr.p->fragPtrI; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); LocalDLFifoList<ScanRecord> queue(c_scanRecordPool, tFragPtr.p->m_queuedScans); if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ jam(); queue.release(scanptr); return; } if(scanptr.p->scanKeyinfoFlag){ jam(); ScanRecordPtr tmp; #ifdef TRACE_SCAN_TAKEOVER ndbout_c("removing (%d %d)", scanptr.p->scanNumber, scanptr.p->fragPtrI); #endif c_scanTakeOverHash.remove(tmp, * scanptr.p); ndbrequire(tmp.p == scanptr.p); } LocalDLList<ScanRecord> scans(c_scanRecordPool, tFragPtr.p->m_activeScans); scans.release(scanptr); const Uint32 scanNumber = scanptr.p->scanNumber; ndbrequire(!tFragPtr.p->m_scanNumberMask.get(scanNumber)); ScanRecordPtr restart; /** * Start on of queued scans */ if(scanNumber == NR_ScanNo || !queue.first(restart)){ jam(); tFragPtr.p->m_scanNumberMask.set(scanNumber); return; } if(ERROR_INSERTED(5034)){ jam(); tFragPtr.p->m_scanNumberMask.set(scanNumber); return; } ScanRecordPtr tmpScan = scanptr; TcConnectionrecPtr tmpTc = tcConnectptr; tcConnectptr.i = restart.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); restart.p->scanNumber = scanNumber; restart.p->scanState = ScanRecord::WAIT_ACC_SCAN; queue.remove(restart); scans.add(restart); if(restart.p->scanKeyinfoFlag){ jam(); #ifdef VM_TRACE ScanRecordPtr tmp; ndbrequire(!c_scanTakeOverHash.find(tmp, * restart.p)); #endif c_scanTakeOverHash.add(restart); #ifdef TRACE_SCAN_TAKEOVER ndbout_c("adding-r (%d %d)", restart.p->scanNumber, restart.p->fragPtrI); #endif } scanptr = restart; continueAfterReceivingAllAiLab(signal); scanptr = tmpScan; tcConnectptr = tmpTc; }//Dblqh::finishScanrec() /* ========================================================================= * ======= RELEASE SCAN RECORD ======= * * RELEASE A SCAN RECORD TO THE FREELIST. * ========================================================================= */ void Dblqh::releaseScanrec(Signal* signal) { scanptr.p->scanState = ScanRecord::SCAN_FREE; scanptr.p->scanType = ScanRecord::ST_IDLE; scanptr.p->scanTcWaiting = ZFALSE; cbookedAccOps -= scanptr.p->m_max_batch_size_rows; cscanNoFreeRec++; }//Dblqh::releaseScanrec() /* ------------------------------------------------------------------------ * ------- SEND KEYINFO20 TO API ------- * * ------------------------------------------------------------------------ */ void Dblqh::sendKeyinfo20(Signal* signal, ScanRecord * scanP, TcConnectionrec * tcConP) { ndbrequire(scanP->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN); KeyInfo20 * keyInfo = (KeyInfo20 *)&signal->theData[0]; DatabufPtr TdataBuf; TdataBuf.i = tcConP->firstTupkeybuf; Uint32 keyLen = tcConP->primKeyLen; const Uint32 dataBufSz = cdatabufFileSize; /** * Note that this code requires signal->theData to be big enough for * a entire key */ ndbrequire(keyLen * 4 <= sizeof(signal->theData)); const BlockReference ref = scanP->scanApiBlockref; const Uint32 scanOp = scanP->m_curr_batch_size_rows; const Uint32 nodeId = refToNode(ref); const bool connectedToNode = getNodeInfo(nodeId).m_connected; const Uint32 type = getNodeInfo(nodeId).m_type; const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::REP); const bool old_dest = (getNodeInfo(nodeId).m_version < MAKE_VERSION(3,5,0)); const bool longable = true; // TODO is_api && !old_dest; Uint32 * dst = keyInfo->keyData; dst += nodeId == getOwnNodeId() ? 0 : KeyInfo20::DataLength; /** * Copy keydata from data buffer into signal * */ for(Uint32 i = 0; i < keyLen; i += 4){ ptrCheckGuard(TdataBuf, dataBufSz, databuf); * dst++ = TdataBuf.p->data[0]; * dst++ = TdataBuf.p->data[1]; * dst++ = TdataBuf.p->data[2]; * dst++ = TdataBuf.p->data[3]; TdataBuf.i = TdataBuf.p->nextDatabuf; } keyInfo->clientOpPtr = scanP->scanApiOpPtr; keyInfo->keyLen = keyLen; keyInfo->scanInfo_Node = KeyInfo20::setScanInfo(scanOp, scanP->scanNumber)+ (getOwnNodeId() << 20); keyInfo->transId1 = tcConP->transid[0]; keyInfo->transId2 = tcConP->transid[1]; Uint32 * src = signal->theData+25; if(connectedToNode){ jam(); if(nodeId != getOwnNodeId()){ jam(); if(keyLen <= KeyInfo20::DataLength || !longable) { while(keyLen > KeyInfo20::DataLength){ jam(); MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength); sendSignal(ref, GSN_KEYINFO20, signal, 25, JBB); src += KeyInfo20::DataLength;; keyLen -= KeyInfo20::DataLength; } while(keyLen >= KeyInfo20::DataLength); MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen); sendSignal(ref, GSN_KEYINFO20, signal, KeyInfo20::HeaderLength+keyLen, JBB); return; } LinearSectionPtr ptr[3]; ptr[0].p = src; ptr[0].sz = keyLen; sendSignal(ref, GSN_KEYINFO20, signal, KeyInfo20::HeaderLength, JBB, ptr, 1); return; } EXECUTE_DIRECT(refToBlock(ref), GSN_KEYINFO20, signal, KeyInfo20::HeaderLength + keyLen); jamEntry(); return; } /** * If this node does not have a direct connection * to the receiving node we want to send the signals * routed via the node that controls this read */ Uint32 routeBlockref = tcConP->clientBlockref; if(keyLen < KeyInfo20::DataLength || !longable){ jam(); while (keyLen > (KeyInfo20::DataLength - 1)) { jam(); MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength - 1); keyInfo->keyData[KeyInfo20::DataLength-1] = ref; sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, 25, JBB); src += KeyInfo20::DataLength - 1; keyLen -= KeyInfo20::DataLength - 1; } MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen); keyInfo->keyData[keyLen] = ref; sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, KeyInfo20::HeaderLength+keyLen+1, JBB); return; } keyInfo->keyData[0] = ref; LinearSectionPtr ptr[3]; ptr[0].p = src; ptr[0].sz = keyLen; sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, KeyInfo20::HeaderLength+1, JBB, ptr, 1); return; } /* ------------------------------------------------------------------------ * ------- SEND SCAN_FRAGCONF TO TC THAT CONTROLS THE SCAN ------- * * ------------------------------------------------------------------------ */ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) { Uint32 completed_ops= scanptr.p->m_curr_batch_size_rows; Uint32 total_len= scanptr.p->m_curr_batch_size_bytes; scanptr.p->scanTcWaiting = ZFALSE; if(ERROR_INSERTED(5037)){ CLEAR_ERROR_INSERT_VALUE; return; } ScanFragConf * conf = (ScanFragConf*)&signal->theData[0]; NodeId tc_node_id= refToNode(tcConnectptr.p->clientBlockref); Uint32 trans_id1= tcConnectptr.p->transid[0]; Uint32 trans_id2= tcConnectptr.p->transid[1]; conf->senderData = tcConnectptr.p->clientConnectrec; conf->completedOps = completed_ops; conf->fragmentCompleted = scanCompleted; conf->transId1 = trans_id1; conf->transId2 = trans_id2; conf->total_len= total_len; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGCONF, signal, ScanFragConf::SignalLength, JBB); }//Dblqh::sendScanFragConf() /* ######################################################################### */ /* ####### NODE RECOVERY MODULE ####### */ /* */ /* ######################################################################### */ /*---------------------------------------------------------------------------*/ /* */ /* THIS MODULE IS USED WHEN A NODE HAS FAILED. IT PERFORMS A COPY OF A */ /* FRAGMENT TO A NEW REPLICA OF THE FRAGMENT. IT DOES ALSO SHUT DOWN ALL */ /* CONNECTIONS TO THE FAILED NODE. */ /*---------------------------------------------------------------------------*/ void Dblqh::calculateHash(Signal* signal) { DatabufPtr locDatabufptr; UintR Ti; UintR Tdata0; UintR Tdata1; UintR Tdata2; UintR Tdata3; UintR* Tdata32; Uint64 Tdata[512]; Tdata32 = (UintR*)&Tdata[0]; Tdata0 = tcConnectptr.p->tupkeyData[0]; Tdata1 = tcConnectptr.p->tupkeyData[1]; Tdata2 = tcConnectptr.p->tupkeyData[2]; Tdata3 = tcConnectptr.p->tupkeyData[3]; Tdata32[0] = Tdata0; Tdata32[1] = Tdata1; Tdata32[2] = Tdata2; Tdata32[3] = Tdata3; locDatabufptr.i = tcConnectptr.p->firstTupkeybuf; Ti = 4; while (locDatabufptr.i != RNIL) { ptrCheckGuard(locDatabufptr, cdatabufFileSize, databuf); 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 tcConnectptr.p->hashValue = md5_hash((Uint64*)&Tdata32[0], (UintR)tcConnectptr.p->primKeyLen); }//Dblqh::calculateHash() /* *************************************** */ /* COPY_FRAGREQ: Start copying a fragment */ /* *************************************** */ void Dblqh::execCOPY_FRAGREQ(Signal* signal) { jamEntry(); const CopyFragReq * const copyFragReq = (CopyFragReq *)&signal->theData[0]; tabptr.i = copyFragReq->tableId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); const Uint32 fragId = copyFragReq->fragId; const Uint32 copyPtr = copyFragReq->userPtr; const Uint32 userRef = copyFragReq->userRef; const Uint32 nodeId = copyFragReq->nodeId; ndbrequire(cnoActiveCopy < 3); ndbrequire(getFragmentrec(signal, fragId)); ndbrequire(fragptr.p->copyFragState == ZIDLE); ndbrequire(cfirstfreeTcConrec != RNIL); ndbrequire(fragptr.p->m_scanNumberMask.get(NR_ScanNo)); fragptr.p->fragDistributionKey = copyFragReq->distributionKey; if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) { jam(); /** * Ordered index doesn't need to be copied */ CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0]; conf->userPtr = copyPtr; conf->sendingNodeId = cownNodeid; conf->startingNodeId = nodeId; conf->tableId = tabptr.i; conf->fragId = fragId; sendSignal(userRef, GSN_COPY_FRAGCONF, signal, CopyFragConf::SignalLength, JBB); return; }//if LocalDLList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans); ndbrequire(scans.seize(scanptr)); /* ------------------------------------------------------------------------- */ // We keep track of how many operation records in ACC that has been booked. // Copy fragment has records always booked and thus need not book any. The // most operations in parallel use is the m_max_batch_size_rows. // This variable has to be set-up here since it is used by releaseScanrec // to unbook operation records in ACC. /* ------------------------------------------------------------------------- */ scanptr.p->m_max_batch_size_rows = 0; scanptr.p->rangeScan = 0; seizeTcrec(); /** * Remove implicit cast/usage of CopyFragReq */ //initCopyrec(signal); scanptr.p->copyPtr = copyPtr; scanptr.p->scanType = ScanRecord::COPY; scanptr.p->scanApiBlockref = userRef; scanptr.p->scanNodeId = nodeId; scanptr.p->scanTcrec = tcConnectptr.i; scanptr.p->scanSchemaVersion = copyFragReq->schemaVersion; scanptr.p->scanCompletedStatus = ZFALSE; scanptr.p->scanErrorCounter = 0; scanptr.p->scanNumber = NR_ScanNo; scanptr.p->scanKeyinfoFlag = 0; // Don't put into hash scanptr.p->fragPtrI = fragptr.i; fragptr.p->m_scanNumberMask.clear(NR_ScanNo); initScanTc(signal, 0, (DBLQH << 20) + (cownNodeid << 8), fragId, copyFragReq->nodeId); cactiveCopy[cnoActiveCopy] = fragptr.i; cnoActiveCopy++; tcConnectptr.p->copyCountWords = 0; tcConnectptr.p->tcOprec = tcConnectptr.i; tcConnectptr.p->schemaVersion = scanptr.p->scanSchemaVersion; scanptr.p->scanState = ScanRecord::WAIT_ACC_COPY; AccScanReq * req = (AccScanReq*)&signal->theData[0]; req->senderData = scanptr.i; req->senderRef = cownref; req->tableId = tabptr.i; req->fragmentNo = fragId; req->requestInfo = 0; AccScanReq::setLockMode(req->requestInfo, 0); AccScanReq::setKeyinfoFlag(req->requestInfo, 1); AccScanReq::setReadCommittedFlag(req->requestInfo, 0); req->transId1 = tcConnectptr.p->transid[0]; req->transId2 = tcConnectptr.p->transid[1]; req->savePointId = tcConnectptr.p->savePointId; sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_SCANREQ, signal, AccScanReq::SignalLength, JBB); return; }//Dblqh::execCOPY_FRAGREQ() void Dblqh::accScanConfCopyLab(Signal* signal) { AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0]; tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); /*--------------------------------------------------------------------------*/ /* PRECONDITION: SCAN_STATE = WAIT_ACC_COPY */ /*--------------------------------------------------------------------------*/ if (accScanConf->flag == AccScanConf::ZEMPTY_FRAGMENT) { jam(); /*---------------------------------------------------------------------------*/ /* THE FRAGMENT WAS EMPTY. */ /* REPORT SUCCESSFUL COPYING. */ /*---------------------------------------------------------------------------*/ tupCopyCloseConfLab(signal); return; }//if scanptr.p->scanAccPtr = accScanConf->accPtr; scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_COPY; signal->theData[0] = tcConnectptr.p->tupConnectrec; signal->theData[1] = tcConnectptr.p->tableref; signal->theData[2] = scanptr.p->scanSchemaVersion; signal->theData[3] = ZSTORED_PROC_COPY; // theData[4] is not used in TUP with ZSTORED_PROC_COPY sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); return; }//Dblqh::accScanConfCopyLab() /*---------------------------------------------------------------------------*/ /* ENTER STORED_PROCCONF WITH */ /* TC_CONNECTPTR, */ /* TSTORED_PROC_ID */ /*---------------------------------------------------------------------------*/ void Dblqh::storedProcConfCopyLab(Signal* signal) { /*---------------------------------------------------------------------------*/ /* PRECONDITION: SCAN_STATE = WAIT_STORED_PROC_COPY */ /*---------------------------------------------------------------------------*/ fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); /*---------------------------------------------------------------------------*/ /* THE COPY PROCESS HAVE BEEN COMPLETED, MOST LIKELY DUE TO A NODE FAILURE.*/ /*---------------------------------------------------------------------------*/ closeCopyLab(signal); return; }//if scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY; switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::COPY_FIRST_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: jam(); systemErrorLab(signal); return; break; }//switch continueFirstCopyAfterBlockedLab(signal); return; }//Dblqh::storedProcConfCopyLab() void Dblqh::continueFirstCopyAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = RNIL; signal->theData[2] = NextScanReq::ZSCAN_NEXT; sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); return; }//Dblqh::continueFirstCopyAfterBlockedLab() /*---------------------------------------------------------------------------*/ /* ENTER NEXT_SCANCONF WITH */ /* SCANPTR, */ /* TFRAGID, */ /* TACC_OPPTR, */ /* TLOCAL_KEY1, */ /* TLOCAL_KEY2, */ /* TKEY_LENGTH, */ /* TKEY1, */ /* TKEY2, */ /* TKEY3, */ /* TKEY4 */ /*---------------------------------------------------------------------------*/ /* PRECONDITION: SCAN_STATE = WAIT_NEXT_SCAN_COPY */ /*---------------------------------------------------------------------------*/ void Dblqh::nextScanConfCopyLab(Signal* signal) { NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0]; tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); if (nextScanConf->fragId == RNIL) { jam(); /*---------------------------------------------------------------------------*/ /* THERE ARE NO MORE TUPLES TO FETCH. WE NEED TO CLOSE */ /* THE COPY IN ACC AND DELETE THE STORED PROCEDURE IN TUP */ /*---------------------------------------------------------------------------*/ releaseActiveFrag(signal); if (tcConnectptr.p->copyCountWords == 0) { closeCopyLab(signal); return; }//if /*---------------------------------------------------------------------------*/ // Wait until copying is completed also at the starting node before reporting // completion. Signal completion through scanCompletedStatus-flag. /*---------------------------------------------------------------------------*/ scanptr.p->scanCompletedStatus = ZTRUE; return; }//if // If accOperationPtr == RNIL no record was returned by ACC if (nextScanConf->accOperationPtr == RNIL) { jam(); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP; sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB); return; } set_acc_ptr_in_scan_record(scanptr.p, 0, nextScanConf->accOperationPtr); initCopyTc(signal); if (tcConnectptr.p->primKeyLen > 4) { jam(); tcConnectptr.p->save1 = 4; scanptr.p->scanState = ScanRecord::WAIT_COPY_KEYINFO; return; }//if copySendTupkeyReqLab(signal); return; }//Dblqh::nextScanConfCopyLab() void Dblqh::copySendTupkeyReqLab(Signal* signal) { Uint32 reqinfo = 0; Uint32 tupFragPtr; reqinfo = reqinfo + (tcConnectptr.p->operation << 6); reqinfo = reqinfo + (tcConnectptr.p->opExec << 10); tcConnectptr.p->transactionState = TcConnectionrec::COPY_TUPKEY; scanptr.p->scanState = ScanRecord::WAIT_TUPKEY_COPY; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (fragptr.p->fragId == scanptr.p->scanLocalFragid) { jam(); tupFragPtr = fragptr.p->tupFragptr[0]; } else { jam(); tupFragPtr = fragptr.p->tupFragptr[1]; }//if { TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); tupKeyReq->connectPtr = tcConnectptr.p->tupConnectrec; tupKeyReq->request = reqinfo; tupKeyReq->tableRef = tcConnectptr.p->tableref; tupKeyReq->fragId = scanptr.p->scanLocalFragid; tupKeyReq->keyRef1 = scanptr.p->scanLocalref[0]; tupKeyReq->keyRef2 = scanptr.p->scanLocalref[1]; tupKeyReq->attrBufLen = 0; tupKeyReq->opRef = tcConnectptr.i; tupKeyReq->applRef = cownref; tupKeyReq->schemaVersion = scanptr.p->scanSchemaVersion; tupKeyReq->storedProcedure = scanptr.p->scanStoredProcId; tupKeyReq->transId1 = tcConnectptr.p->transid[0]; tupKeyReq->transId2 = tcConnectptr.p->transid[1]; tupKeyReq->fragPtr = tupFragPtr; tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; tupKeyReq->savePointId = tcConnectptr.p->savePointId; Uint32 blockNo = refToBlock(tcConnectptr.p->tcTupBlockref); EXECUTE_DIRECT(blockNo, GSN_TUPKEYREQ, signal, TupKeyReq::SignalLength); } }//Dblqh::copySendTupkeyReqLab() /*---------------------------------------------------------------------------*/ /* USED IN COPYING OPERATION TO RECEIVE ATTRINFO FROM TUP. */ /*---------------------------------------------------------------------------*/ /* ************>> */ /* TRANSID_AI > */ /* ************>> */ void Dblqh::execTRANSID_AI(Signal* signal) { jamEntry(); tcConnectptr.i = signal->theData[0]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); Uint32 length = signal->length() - 3; ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::COPY_TUPKEY); Uint32 * src = &signal->theData[3]; while(length > 22){ if (saveTupattrbuf(signal, src, 22) == ZOK) { ; } else { jam(); tcConnectptr.p->errorCode = ZGET_ATTRINBUF_ERROR; return; }//if src += 22; length -= 22; } if (saveTupattrbuf(signal, src, length) == ZOK) { return; } jam(); tcConnectptr.p->errorCode = ZGET_ATTRINBUF_ERROR; }//Dblqh::execTRANSID_AI() /*--------------------------------------------------------------------------*/ /* ENTER TUPKEYCONF WITH */ /* TC_CONNECTPTR, */ /* TDATA2, */ /* TDATA3, */ /* TDATA4, */ /* TDATA5 */ /*--------------------------------------------------------------------------*/ /* PRECONDITION: TRANSACTION_STATE = COPY_TUPKEY */ /*--------------------------------------------------------------------------*/ void Dblqh::copyTupkeyConfLab(Signal* signal) { const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr(); UintR readLength = tupKeyConf->readLength; scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); releaseActiveFrag(signal); if (tcConnectptr.p->errorCode != 0) { jam(); closeCopyLab(signal); return; }//if if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); /*---------------------------------------------------------------------------*/ /* THE COPY PROCESS HAVE BEEN CLOSED. MOST LIKELY A NODE FAILURE. */ /*---------------------------------------------------------------------------*/ closeCopyLab(signal); return; }//if tcConnectptr.p->totSendlenAi = readLength; tcConnectptr.p->connectState = TcConnectionrec::COPY_CONNECTED; calculateHash(signal); /*---------------------------------------------------------------------------*/ // To avoid using up to many operation records in ACC we will increase the // constant to ensure that we never send more than 40 records at a time. // This is where the constant 56 comes from. For long records this constant // will not matter that much. The current maximum is 6000 words outstanding // (including a number of those 56 words not really sent). We also have to // ensure that there are never more simultaneous usage of these operation // records to ensure that node recovery does not fail because of simultaneous // scanning. /*---------------------------------------------------------------------------*/ UintR TnoOfWords = readLength + tcConnectptr.p->primKeyLen; TnoOfWords = TnoOfWords + MAGIC_CONSTANT; TnoOfWords = TnoOfWords + (TnoOfWords >> 2); /*----------------------------------------------------------------- * NOTE for transid1! * Transid1 in the tcConnection record is used load regulate the * copy(node recovery) process. * The number of outstanding words are written in the transid1 * variable. This will be sent to the starting node in the * LQHKEYREQ signal and when the answer is returned in the LQHKEYCONF * we can reduce the number of outstanding words and check to see * if more LQHKEYREQ signals should be sent. * * However efficient this method is rather unsafe in such way that * it overwrites the transid1 original data. * * Also see TR 587. *----------------------------------------------------------------*/ tcConnectptr.p->transid[0] = TnoOfWords; // Data overload, see note! packLqhkeyreqLab(signal); tcConnectptr.p->copyCountWords += TnoOfWords; scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY; if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) { nextRecordCopy(signal); return; }//if return; }//Dblqh::copyTupkeyConfLab() /*---------------------------------------------------------------------------*/ /* ENTER LQHKEYCONF */ /*---------------------------------------------------------------------------*/ /* PRECONDITION: CONNECT_STATE = COPY_CONNECTED */ /*---------------------------------------------------------------------------*/ void Dblqh::copyCompletedLab(Signal* signal) { const LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); ndbrequire(tcConnectptr.p->transid[1] == lqhKeyConf->transId2); scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); if (tcConnectptr.p->copyCountWords >= cmaxWordsAtNodeRec) { tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note! if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); /*---------------------------------------------------------------------------*/ // Copy to complete, we will not start any new copying. /*---------------------------------------------------------------------------*/ closeCopyLab(signal); return; }//if if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) { jam(); nextRecordCopy(signal); }//if return; }//if tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note! ndbrequire(tcConnectptr.p->copyCountWords <= cmaxWordsAtNodeRec); if (tcConnectptr.p->copyCountWords > 0) { jam(); return; }//if /*---------------------------------------------------------------------------*/ // No more outstanding copies. We will only start new ones from here if it was // stopped before and this only happens when copyCountWords is bigger than the // threshold value. Since this did not occur we must be waiting for completion. // Check that this is so. If not we crash to find out what is going on. /*---------------------------------------------------------------------------*/ if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); closeCopyLab(signal); return; }//if if (scanptr.p->scanState == ScanRecord::WAIT_LQHKEY_COPY) { jam(); /*---------------------------------------------------------------------------*/ // Make sure that something is in progress. Otherwise we will simply stop // and nothing more will happen. /*---------------------------------------------------------------------------*/ systemErrorLab(signal); return; }//if return; }//Dblqh::copyCompletedLab() void Dblqh::nextRecordCopy(Signal* signal) { fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanState != ScanRecord::WAIT_LQHKEY_COPY) { jam(); /*---------------------------------------------------------------------------*/ // Make sure that nothing is in progress. Otherwise we will have to simultaneous // scans on the same record and this will certainly lead to unexpected // behaviour. /*---------------------------------------------------------------------------*/ systemErrorLab(signal); return; }//if scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY; switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::COPY_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: jam(); systemErrorLab(signal); return; break; }//switch continueCopyAfterBlockedLab(signal); return; }//Dblqh::nextRecordCopy() void Dblqh::continueCopyAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); tcConnectptr.p->errorCode = 0; Uint32 acc_op_ptr= get_acc_ptr_from_scan_record(scanptr.p, 0, false); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = acc_op_ptr; signal->theData[2] = NextScanReq::ZSCAN_NEXT_COMMIT; sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); return; }//Dblqh::continueCopyAfterBlockedLab() void Dblqh::copyLqhKeyRefLab(Signal* signal) { ndbrequire(tcConnectptr.p->transid[1] == signal->theData[4]); tcConnectptr.p->copyCountWords -= signal->theData[3]; scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanErrorCounter++; tcConnectptr.p->errorCode = terrorCode; closeCopyLab(signal); return; }//Dblqh::copyLqhKeyRefLab() void Dblqh::closeCopyLab(Signal* signal) { if (tcConnectptr.p->copyCountWords > 0) { /*---------------------------------------------------------------------------*/ // We are still waiting for responses from the starting node. // Wait until all of those have arrived until we start the // close process. /*---------------------------------------------------------------------------*/ jam(); return; }//if tcConnectptr.p->transid[0] = 0; tcConnectptr.p->transid[1] = 0; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); scanptr.p->scanState = ScanRecord::WAIT_CLOSE_COPY; switch (fragptr.p->fragStatus) { case Fragrecord::FSACTIVE: jam(); linkActiveFrag(signal); break; case Fragrecord::BLOCKED: jam(); linkFragQueue(signal); tcConnectptr.p->transactionState = TcConnectionrec::COPY_CLOSE_STOPPED; return; break; case Fragrecord::FREE: jam(); case Fragrecord::ACTIVE_CREATION: jam(); case Fragrecord::CRASH_RECOVERING: jam(); case Fragrecord::DEFINED: jam(); case Fragrecord::REMOVING: jam(); default: jam(); systemErrorLab(signal); return; break; }//switch continueCloseCopyAfterBlockedLab(signal); return; }//Dblqh::closeCopyLab() void Dblqh::continueCloseCopyAfterBlockedLab(Signal* signal) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = RNIL; signal->theData[2] = ZCOPY_CLOSE; sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); return; }//Dblqh::continueCloseCopyAfterBlockedLab() /*---------------------------------------------------------------------------*/ /* ENTER NEXT_SCANCONF WITH */ /* SCANPTR, */ /* TFRAGID, */ /* TACC_OPPTR, */ /* TLOCAL_KEY1, */ /* TLOCAL_KEY2, */ /* TKEY_LENGTH, */ /* TKEY1, */ /* TKEY2, */ /* TKEY3, */ /* TKEY4 */ /*---------------------------------------------------------------------------*/ /* PRECONDITION: SCAN_STATE = WAIT_CLOSE_COPY */ /*---------------------------------------------------------------------------*/ void Dblqh::accCopyCloseConfLab(Signal* signal) { tcConnectptr.i = scanptr.p->scanTcrec; scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_COPY; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); signal->theData[0] = tcConnectptr.p->tupConnectrec; signal->theData[1] = tcConnectptr.p->tableref; signal->theData[2] = scanptr.p->scanSchemaVersion; signal->theData[3] = ZDELETE_STORED_PROC_ID; signal->theData[4] = scanptr.p->scanStoredProcId; sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); return; }//Dblqh::accCopyCloseConfLab() /*---------------------------------------------------------------------------*/ /* ENTER STORED_PROCCONF WITH */ /* TC_CONNECTPTR, */ /* TSTORED_PROC_ID */ /*---------------------------------------------------------------------------*/ /* PRECONDITION: SCAN_STATE = WAIT_DELETE_STORED_PROC_ID_COPY */ /*---------------------------------------------------------------------------*/ void Dblqh::tupCopyCloseConfLab(Signal* signal) { fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->copyFragState = ZIDLE; if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) { jam(); tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0]; ref->userPtr = scanptr.p->copyPtr; ref->sendingNodeId = cownNodeid; ref->startingNodeId = scanptr.p->scanNodeId; ref->tableId = fragptr.p->tabRef; ref->fragId = fragptr.p->fragId; ref->errorCode = ZNODE_FAILURE_ERROR; sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGREF, signal, CopyFragRef::SignalLength, JBB); } else { if (scanptr.p->scanErrorCounter > 0) { jam(); CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0]; ref->userPtr = scanptr.p->copyPtr; ref->sendingNodeId = cownNodeid; ref->startingNodeId = scanptr.p->scanNodeId; ref->tableId = fragptr.p->tabRef; ref->fragId = fragptr.p->fragId; ref->errorCode = tcConnectptr.p->errorCode; sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGREF, signal, CopyFragRef::SignalLength, JBB); } else { jam(); CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0]; conf->userPtr = scanptr.p->copyPtr; conf->sendingNodeId = cownNodeid; conf->startingNodeId = scanptr.p->scanNodeId; conf->tableId = tcConnectptr.p->tableref; conf->fragId = tcConnectptr.p->fragmentid; sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGCONF, signal, CopyFragConf::SignalLength, JBB); }//if }//if releaseActiveCopy(signal); tcConnectptr.p->tcScanRec = RNIL; finishScanrec(signal); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); releaseScanrec(signal); }//Dblqh::tupCopyCloseConfLab() /*---------------------------------------------------------------------------*/ /* A NODE FAILURE OCCURRED DURING THE COPY PROCESS. WE NEED TO CLOSE THE */ /* COPY PROCESS SINCE A NODE FAILURE DURING THE COPY PROCESS WILL ALSO */ /* FAIL THE NODE THAT IS TRYING TO START-UP. */ /*---------------------------------------------------------------------------*/ void Dblqh::closeCopyRequestLab(Signal* signal) { scanptr.p->scanErrorCounter++; switch (scanptr.p->scanState) { case ScanRecord::WAIT_TUPKEY_COPY: case ScanRecord::WAIT_COPY_KEYINFO: case ScanRecord::WAIT_NEXT_SCAN_COPY: jam(); /*---------------------------------------------------------------------------*/ /* SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN. */ // ALSO SET NO OF WORDS OUTSTANDING TO ZERO TO AVOID ETERNAL WAIT. /*---------------------------------------------------------------------------*/ scanptr.p->scanCompletedStatus = ZTRUE; tcConnectptr.p->copyCountWords = 0; break; case ScanRecord::WAIT_ACC_COPY: case ScanRecord::WAIT_STORED_PROC_COPY: jam(); /*---------------------------------------------------------------------------*/ /* WE ARE CURRENTLY STARTING UP THE SCAN. SET COMPLETED STATUS AND WAIT FOR*/ /* COMPLETION OF STARTUP. */ /*---------------------------------------------------------------------------*/ scanptr.p->scanCompletedStatus = ZTRUE; break; case ScanRecord::WAIT_CLOSE_COPY: case ScanRecord::WAIT_DELETE_STORED_PROC_ID_COPY: jam(); /*---------------------------------------------------------------------------*/ /* CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING. */ /*---------------------------------------------------------------------------*/ break; case ScanRecord::WAIT_LQHKEY_COPY: jam(); /*---------------------------------------------------------------------------*/ /* WE ARE WAITING FOR THE FAILED NODE. THE NODE WILL NEVER COME BACK. */ // WE NEED TO START THE FAILURE HANDLING IMMEDIATELY. // ALSO SET NO OF WORDS OUTSTANDING TO ZERO TO AVOID ETERNAL WAIT. /*---------------------------------------------------------------------------*/ tcConnectptr.p->copyCountWords = 0; closeCopyLab(signal); break; default: ndbrequire(false); break; }//switch return; }//Dblqh::closeCopyRequestLab() /* ****************************************************** */ /* COPY_ACTIVEREQ: Change state of a fragment to ACTIVE. */ /* ****************************************************** */ void Dblqh::execCOPY_ACTIVEREQ(Signal* signal) { CRASH_INSERTION(5026); const CopyActiveReq * const req = (CopyActiveReq *)&signal->theData[0]; jamEntry(); Uint32 masterPtr = req->userPtr; BlockReference masterRef = req->userRef; tabptr.i = req->tableId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); Uint32 fragId = req->fragId; ndbrequire(getFragmentrec(signal, fragId)); fragptr.p->fragDistributionKey = req->distributionKey; ndbrequire(cnoActiveCopy < 3); cactiveCopy[cnoActiveCopy] = fragptr.i; cnoActiveCopy++; fragptr.p->masterBlockref = masterRef; fragptr.p->masterPtr = masterPtr; if (fragptr.p->fragStatus == Fragrecord::FSACTIVE) { jam(); /*------------------------------------------------------*/ /* PROCESS HAVE ALREADY BEEN STARTED BY PREVIOUS */ /* MASTER. WE HAVE ALREADY SET THE PROPER MASTER */ /* BLOCK REFERENCE. */ /*------------------------------------------------------*/ if (fragptr.p->activeTcCounter == 0) { jam(); /*------------------------------------------------------*/ /* PROCESS WAS EVEN COMPLETED. */ /*------------------------------------------------------*/ sendCopyActiveConf(signal, tabptr.i); }//if return; }//if fragptr.p->fragStatus = Fragrecord::FSACTIVE; if (fragptr.p->lcpFlag == Fragrecord::LCP_STATE_TRUE) { jam(); fragptr.p->logFlag = Fragrecord::STATE_TRUE; }//if fragptr.p->activeTcCounter = 1; /*------------------------------------------------------*/ /* SET IT TO ONE TO ENSURE THAT IT IS NOT POSSIBLE*/ /* TO DECREASE IT TO ZERO UNTIL WE HAVE COMPLETED */ /* THE SCAN. */ /*------------------------------------------------------*/ signal->theData[0] = ZSCAN_TC_CONNECT; signal->theData[1] = 0; signal->theData[2] = tabptr.i; signal->theData[3] = fragId; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); return; }//Dblqh::execCOPY_ACTIVEREQ() void Dblqh::scanTcConnectLab(Signal* signal, Uint32 tstartTcConnect, Uint32 fragId) { Uint32 tendTcConnect; ndbrequire(getFragmentrec(signal, fragId)); if ((tstartTcConnect + 200) >= ctcConnectrecFileSize) { jam(); tendTcConnect = ctcConnectrecFileSize - 1; } else { jam(); tendTcConnect = tstartTcConnect + 200; }//if for (tcConnectptr.i = tstartTcConnect; tcConnectptr.i <= tendTcConnect; tcConnectptr.i++) { jam(); ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) { switch (tcConnectptr.p->logWriteState) { case TcConnectionrec::NOT_WRITTEN: jam(); if (fragptr.i == tcConnectptr.p->fragmentptr) { jam(); fragptr.p->activeTcCounter = fragptr.p->activeTcCounter + 1; tcConnectptr.p->logWriteState = TcConnectionrec::NOT_WRITTEN_WAIT; }//if break; default: jam(); /*empty*/; break; }//switch }//if }//for if (tendTcConnect < (ctcConnectrecFileSize - 1)) { jam(); signal->theData[0] = ZSCAN_TC_CONNECT; signal->theData[1] = tendTcConnect + 1; signal->theData[2] = tabptr.i; signal->theData[3] = fragId; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); } else { jam(); /*------------------------------------------------------*/ /* THE SCAN HAVE BEEN COMPLETED. WE CHECK IF ALL */ /* OPERATIONS HAVE ALREADY BEEN COMPLETED. */ /*------------------------------------------------------*/ ndbrequire(fragptr.p->activeTcCounter > 0); fragptr.p->activeTcCounter--; if (fragptr.p->activeTcCounter == 0) { jam(); /*------------------------------------------------------*/ /* SET START GLOBAL CHECKPOINT TO THE NEXT */ /* CHECKPOINT WE HAVE NOT YET HEARD ANYTHING ABOUT*/ /* THIS GCP WILL BE COMPLETELY COVERED BY THE LOG.*/ /*------------------------------------------------------*/ fragptr.p->startGci = cnewestGci + 1; sendCopyActiveConf(signal, tabptr.i); }//if }//if return; }//Dblqh::scanTcConnectLab() /*---------------------------------------------------------------------------*/ /* A NEW MASTER IS REQUESTING THE STATE IN LQH OF THE COPY FRAGMENT PARTS. */ /*---------------------------------------------------------------------------*/ /* ***************>> */ /* COPY_STATEREQ > */ /* ***************>> */ void Dblqh::execCOPY_STATEREQ(Signal* signal) { jamEntry(); ndbrequire(0) #if 0 Uint32* dataPtr = &signal->theData[2]; BlockReference tmasterBlockref = signal->theData[0]; Uint32 tnoCopy = 0; do { jam(); arrGuard(tnoCopy, 4); fragptr.i = cactiveCopy[tnoCopy]; if (fragptr.i == RNIL) { jam(); break; }//if ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (fragptr.p->copyFragState != ZIDLE) { jam(); /*---------------------------------------------------------------------------*/ /* THIS FRAGMENT IS CURRENTLY ACTIVE IN COPYING THE FRAGMENT. */ /*---------------------------------------------------------------------------*/ scanptr.i = fragptr.p->fragScanRec[NR_ScanNo]; c_scanRecordPool.getPtr(scanptr); if (scanptr.p->scanCompletedStatus == ZTRUE) { jam(); dataPtr[3 + (tnoCopy << 2)] = ZCOPY_CLOSING; } else { jam(); dataPtr[3 + (tnoCopy << 2)] = ZCOPY_ONGOING; }//if dataPtr[2 + (tnoCopy << 2)] = scanptr.p->scanSchemaVersion; scanptr.p->scanApiBlockref = tmasterBlockref; } else { ndbrequire(fragptr.p->activeTcCounter != 0); /*---------------------------------------------------------------------------*/ /* COPY FRAGMENT IS COMPLETED AND WE ARE CURRENTLY GETTING THE STARTING */ /* GCI OF THE NEW REPLICA OF THIS FRAGMENT. */ /*---------------------------------------------------------------------------*/ fragptr.p->masterBlockref = tmasterBlockref; dataPtr[3 + (tnoCopy << 2)] = ZCOPY_ACTIVATION; }//if dataPtr[tnoCopy << 2] = fragptr.p->tabRef; dataPtr[1 + (tnoCopy << 2)] = fragptr.p->fragId; tnoCopy++; } while (tnoCopy < cnoActiveCopy); signal->theData[0] = cownNodeid; signal->theData[1] = tnoCopy; sendSignal(tmasterBlockref, GSN_COPY_STATECONF, signal, 18, JBB); #endif return; }//Dblqh::execCOPY_STATEREQ() /* ========================================================================= */ /* ======= INITIATE TC RECORD AT COPY FRAGMENT ======= */ /* */ /* SUBROUTINE SHORT NAME = ICT */ /* ========================================================================= */ void Dblqh::initCopyTc(Signal* signal) { const NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0]; tcConnectptr.p->primKeyLen = nextScanConf->keyLength; tcConnectptr.p->tupkeyData[0] = nextScanConf->key[0]; tcConnectptr.p->tupkeyData[1] = nextScanConf->key[1]; tcConnectptr.p->tupkeyData[2] = nextScanConf->key[2]; tcConnectptr.p->tupkeyData[3] = nextScanConf->key[3]; scanptr.p->scanLocalref[0] = nextScanConf->localKey[0]; scanptr.p->scanLocalref[1] = nextScanConf->localKey[1]; scanptr.p->scanLocalFragid = nextScanConf->fragId; tcConnectptr.p->operation = ZREAD; tcConnectptr.p->apiVersionNo = 0; tcConnectptr.p->opExec = 0; /* NOT INTERPRETED MODE */ tcConnectptr.p->schemaVersion = scanptr.p->scanSchemaVersion; Uint32 reqinfo = 0; LqhKeyReq::setKeyLen(reqinfo, nextScanConf->keyLength); LqhKeyReq::setLockType(reqinfo, ZINSERT); LqhKeyReq::setDirtyFlag(reqinfo, 1); LqhKeyReq::setSimpleFlag(reqinfo, 1); LqhKeyReq::setOperation(reqinfo, ZWRITE); /* AILen in LQHKEYREQ IS ZERO */ tcConnectptr.p->reqinfo = reqinfo; /* ------------------------------------------------------------------------ */ /* THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL */ /* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET. */ /* ------------------------------------------------------------------------ */ tcConnectptr.p->nodeAfterNext[0] = ZNIL; tcConnectptr.p->nodeAfterNext[1] = ZNIL; tcConnectptr.p->tcBlockref = cownref; tcConnectptr.p->readlenAi = 0; tcConnectptr.p->storedProcId = ZNIL; tcConnectptr.p->opExec = 0; tcConnectptr.p->nextSeqNoReplica = 0; tcConnectptr.p->dirtyOp = ZFALSE; tcConnectptr.p->lastReplicaNo = 0; tcConnectptr.p->currTupAiLen = 0; tcConnectptr.p->tcTimer = cLqhTimeOutCount; }//Dblqh::initCopyTc() /* ------------------------------------------------------------------------- */ /* ------- SEND COPY_ACTIVECONF TO MASTER DIH ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::sendCopyActiveConf(Signal* signal, Uint32 tableId) { releaseActiveCopy(signal); CopyActiveConf * const conf = (CopyActiveConf *)&signal->theData[0]; conf->userPtr = fragptr.p->masterPtr; conf->tableId = tableId; conf->fragId = fragptr.p->fragId; conf->startingNodeId = cownNodeid; conf->startGci = fragptr.p->startGci; sendSignal(fragptr.p->masterBlockref, GSN_COPY_ACTIVECONF, signal, CopyActiveConf::SignalLength, JBB); }//Dblqh::sendCopyActiveConf() /* ########################################################################## * ####### LOCAL CHECKPOINT MODULE ####### * * ########################################################################## * -------------------------------------------------------------------------- * THIS MODULE HANDLES THE EXECUTION AND CONTROL OF LOCAL CHECKPOINTS * IT CONTROLS THE LOCAL CHECKPOINTS IN TUP AND ACC. IT DOES ALSO INTERACT * WITH DIH TO CONTROL WHICH GLOBAL CHECKPOINTS THAT ARE RECOVERABLE * ------------------------------------------------------------------------- */ void Dblqh::execEMPTY_LCP_REQ(Signal* signal) { jamEntry(); CRASH_INSERTION(5008); EmptyLcpReq * const emptyLcpOrd = (EmptyLcpReq*)&signal->theData[0]; lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); Uint32 nodeId = refToNode(emptyLcpOrd->senderRef); lcpPtr.p->m_EMPTY_LCP_REQ.set(nodeId); lcpPtr.p->reportEmpty = true; if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE){ jam(); bool ok = false; switch(clcpCompletedState){ case LCP_IDLE: ok = true; sendEMPTY_LCP_CONF(signal, true); break; case LCP_RUNNING: ok = true; sendEMPTY_LCP_CONF(signal, false); break; case LCP_CLOSE_STARTED: jam(); case ACC_LCP_CLOSE_COMPLETED: jam(); case TUP_LCP_CLOSE_COMPLETED: jam(); ok = true; break; } ndbrequire(ok); }//if return; }//Dblqh::execEMPTY_LCPREQ() void Dblqh::execLCP_FRAG_ORD(Signal* signal) { jamEntry(); CRASH_INSERTION(5010); LcpFragOrd * const lcpFragOrd = (LcpFragOrd *)&signal->theData[0]; Uint32 lcpId = lcpFragOrd->lcpId; lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); lcpPtr.p->lastFragmentFlag = lcpFragOrd->lastFragmentFlag; if (lcpFragOrd->lastFragmentFlag) { jam(); if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { jam(); /* ---------------------------------------------------------- * NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED. * -------------------------------------------------------- */ if (cnoOfFragsCheckpointed > 0) { jam(); completeLcpRoundLab(signal); } else { jam(); sendLCP_COMPLETE_REP(signal, lcpId); }//if } return; }//if tabptr.i = lcpFragOrd->tableId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); ndbrequire(tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE || tabptr.p->tableStatus == Tablerec::TABLE_DEFINED); ndbrequire(getFragmentrec(signal, lcpFragOrd->fragmentId)); lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); ndbrequire(!lcpPtr.p->lcpQueued); if (c_lcpId < lcpFragOrd->lcpId) { jam(); /** * A new LCP */ c_lcpId = lcpFragOrd->lcpId; ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_IDLE); setLogTail(signal, lcpFragOrd->keepGci); ndbrequire(clcpCompletedState == LCP_IDLE); clcpCompletedState = LCP_RUNNING; }//if cnoOfFragsCheckpointed++; if(tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ jam(); LcpRecord::FragOrd fragOrd; fragOrd.fragPtrI = fragptr.i; fragOrd.lcpFragOrd = * lcpFragOrd; sendLCP_FRAG_REP(signal, fragOrd); return; } if (lcpPtr.p->lcpState != LcpRecord::LCP_IDLE) { ndbrequire(lcpPtr.p->lcpQueued == false); lcpPtr.p->lcpQueued = true; lcpPtr.p->queuedFragment.fragPtrI = fragptr.i; lcpPtr.p->queuedFragment.lcpFragOrd = * lcpFragOrd; return; }//if lcpPtr.p->currentFragment.fragPtrI = fragptr.i; lcpPtr.p->currentFragment.lcpFragOrd = * lcpFragOrd; sendLCP_FRAGIDREQ(signal); }//Dblqh::execLCP_FRAGORD() /* -------------------------------------------------------------------------- * PRECONDITION: LCP_PTR:LCP_STATE = WAIT_FRAGID * -------------------------------------------------------------------------- * WE NOW HAVE THE LOCAL FRAGMENTS THAT THE LOCAL CHECKPOINT WILL USE. * -------------------------------------------------------------------------- */ void Dblqh::execLCP_FRAGIDCONF(Signal* signal) { UintR Tfragid[4]; jamEntry(); lcpPtr.i = signal->theData[0]; Uint32 TaccPtr = signal->theData[1]; Uint32 noLocfrag = signal->theData[2]; Tfragid[0] = signal->theData[3]; Tfragid[1] = signal->theData[4]; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_FRAGID); /* ------------------------------------------------------------------------ * NO ERROR CHECKING OF TNO_LOCFRAG VALUE. OUT OF BOUND WILL IMPLY THAT AN * INDEX OUT OF RANGE WILL CAUSE A SYSTEM RESTART WHICH IS DESIRED. * ------------------------------------------------------------------------ */ lcpPtr.p->lcpAccptr = TaccPtr; fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); ndbrequire(noLocfrag - 1 < 2); for (Uint32 Tindex = 0; Tindex < noLocfrag; Tindex++) { jam(); Uint32 fragId = Tfragid[Tindex]; /* ---------------------------------------------------------------------- * THERE IS NO ERROR CHECKING ON PURPOSE. IT IS POSSIBLE TO CALCULATE HOW * MANY LOCAL LCP RECORDS THERE SHOULD BE. IT SHOULD NEVER HAPPEN THAT * THERE IS NO ONE FREE. IF THERE IS NO ONE IT WILL ALSO BE A POINTER * OUT OF RANGE WHICH IS AN ERROR CODE IN ITSELF. REUSES ERROR HANDLING * IN AXE VM. * ---------------------------------------------------------------------- */ seizeLcpLoc(signal); initLcpLocAcc(signal, fragId); seizeLcpLoc(signal); initLcpLocTup(signal, fragId); signal->theData[0] = lcpLocptr.i; signal->theData[1] = cownref; signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; signal->theData[3] = lcpLocptr.p->locFragid; signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; signal->theData[5] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; sendSignal(fragptr.p->tupBlockref, GSN_TUP_PREPLCPREQ, signal, 6, JBB); }//for lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_TUP_PREPLCP; return; }//Dblqh::execLCP_FRAGIDCONF() /* -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_STATE = WAIT_TUPPREPLCP * -------------------------------------------------------------------------- * WE HAVE NOW PREPARED A LOCAL FRAGMENT IN TUP FOR LCP EXECUTION. * -------------------------------------------------------------------------- */ void Dblqh::execTUP_PREPLCPCONF(Signal* signal) { UintR ttupPtr; jamEntry(); lcpLocptr.i = signal->theData[0]; ttupPtr = signal->theData[1]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_TUP_PREPLCP); lcpLocptr.p->tupRef = ttupPtr; lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; checkLcpTupprep(signal); if (lcpPtr.p->lcpState != LcpRecord::LCP_WAIT_HOLDOPS) { jam(); return; }//if fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { jam(); ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); lcpLocptr.p->lcpLocstate = LcpLocRecord::WAIT_LCPHOLDOP; signal->theData[0] = lcpPtr.p->lcpAccptr; signal->theData[1] = lcpLocptr.p->locFragid; signal->theData[2] = 0; signal->theData[3] = lcpLocptr.i; sendSignal(fragptr.p->accBlockref, GSN_LCP_HOLDOPREQ, signal, 4, JBA); lcpLocptr.i = lcpLocptr.p->nextLcpLoc; } while (lcpLocptr.i != RNIL); /* ------------------------------------------------------------------------ * SET STATE ON FRAGMENT TO BLOCKED TO ENSURE THAT NO MORE OPERATIONS ARE * STARTED FROM LQH IN TUP AND ACC UNTIL THE START CHECKPOINT HAS BEEN * COMPLETED. ALSO SET THE LOCAL CHECKPOINT STATE TO WAIT FOR * LCP_HOLDOPCONF * ----------------------------------------------------------------------- */ fragptr.p->fragStatus = Fragrecord::BLOCKED; fragptr.p->fragActiveStatus = ZTRUE; lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_HOLDOPS; return; }//Dblqh::execTUP_PREPLCPCONF() void Dblqh::execTUP_PREPLCPREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execTUP_PREPLCPREF() void Dblqh::execLCP_FRAGIDREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execLCP_FRAGIDREF() /* -------------------------------------------------------------------------- * A NUMBER OF OPERATIONS THAT HAVE BEEN SET ON HOLD IN ACC. MOVE THOSE TO * LIST OF BLOCKED ACC OPERATIONS. IF MORE OPERATIONS ARE BLOCKED GET THOSE * OTHERWISE CONTINUE THE LOCAL CHECKPOINT BY REQUESTING TUP AND ACC TO * WRITE THEIR START CHECKPOINT. * -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = WAIT_LCPHOLDOP * ------------------------------------------------------------------------- */ /* ***************>> */ /* LCP_HOLDOPCONF > */ /* ***************>> */ void Dblqh::execLCP_HOLDOPCONF(Signal* signal) { UintR tnoHoldops; Uint32 Tdata[23]; Uint32 Tlength; jamEntry(); lcpLocptr.i = signal->theData[0]; Tlength = signal->theData[1]; for (Uint32 i = 0; i < 23; i++) Tdata[i] = signal->theData[i + 2]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_LCPHOLDOP); lcpPtr.i = lcpLocptr.p->masterLcpRec; /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ----------------------------------------------------------------------- */ tnoHoldops = Tlength & 65535; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); ndbrequire(tnoHoldops <= 23); for (Uint32 Tindex = 0; Tindex < tnoHoldops; Tindex++) { jam(); tcConnectptr.i = Tdata[Tindex]; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); moveActiveToAcc(signal); }//for if ((Tlength >> 16) == 1) { jam(); /* MORE HOLDOPS NEEDED */ signal->theData[0] = lcpPtr.p->lcpAccptr; signal->theData[1] = lcpLocptr.p->locFragid; signal->theData[2] = 1; signal->theData[3] = lcpLocptr.i; sendSignal(fragptr.p->accBlockref, GSN_LCP_HOLDOPREQ, signal, 4, JBA); return; } else { jam(); /* NO MORE HOLDOPS NEEDED */ lcpLocptr.p->lcpLocstate = LcpLocRecord::HOLDOP_READY; checkLcpHoldop(signal); if (lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_ACTIVE_FINISH) { if (fragptr.p->activeList == RNIL) { jam(); /* ------------------------------------------------------------------ * THERE ARE NO MORE ACTIVE OPERATIONS. IT IS NOW OK TO START THE * LOCAL CHECKPOINT IN BOTH TUP AND ACC. * ----------------------------------------------------------------- */ sendStartLcp(signal); lcpPtr.p->lcpState = LcpRecord::LCP_START_CHKP; } else { jam(); // Set this to signal releaseActiveFrag // that it should check to see if itäs time to call sendStartLcp fragptr.p->lcpRef = lcpPtr.i; }//if }//if }//if /* ----------------------- */ /* ELSE */ /* ------------------------------------------------------------------------ * THERE ARE STILL MORE ACTIVE OPERATIONS. WAIT UNTIL THEY ARE FINSIHED. * THIS IS DISCOVERED WHEN RELEASE_ACTIVE_FRAG IS EXECUTED. * ------------------------------------------------------------------------ * DO NOTHING, EXIT IS EXECUTED BELOW * ----------------------------------------------------------------------- */ return; }//Dblqh::execLCP_HOLDOPCONF() /* ***************> */ /* LCP_HOLDOPREF > */ /* ***************> */ void Dblqh::execLCP_HOLDOPREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execLCP_HOLDOPREF() /* ************************************************************************>> * ACC_LCPSTARTED: Confirm that ACC started local checkpoint and undo * logging is on. * ************************************************************************>> * -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = ACC_WAIT_STARTED * ------------------------------------------------------------------------- */ void Dblqh::execACC_LCPSTARTED(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ----------------------------------------------------------------------- */ lcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_STARTED; lcpStartedLab(signal); return; }//Dblqh::execACC_LCPSTARTED() /* ******************************************> */ /* TUP_LCPSTARTED: Same as above but for TUP. */ /* ******************************************> */ /* -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = TUP_WAIT_STARTED * ------------------------------------------------------------------------- */ void Dblqh::execTUP_LCPSTARTED(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ----------------------------------------------------------------------- */ lcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_STARTED; lcpStartedLab(signal); return; }//Dblqh::execTUP_LCPSTARTED() void Dblqh::lcpStartedLab(Signal* signal) { checkLcpStarted(signal); if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) { jam(); /* ---------------------------------------------------------------------- * THE LOCAL CHECKPOINT HAS BEEN STARTED. IT IS NOW TIME TO * RESTART THE TRANSACTIONS WHICH HAVE BEEN BLOCKED. * --------------------------------------------------------------------- */ fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); /* ---------------------------------------------------------------------- * UPDATE THE MAX_GCI_IN_LCP AND MAX_GCI_COMPLETED_IN_LCP NOW BEFORE * ACTIVATING THE FRAGMENT AGAIN. * --------------------------------------------------------------------- */ ndbrequire(lcpPtr.p->currentFragment.lcpFragOrd.lcpNo < MAX_LCP_STORED); fragptr.p->maxGciInLcp = fragptr.p->newestGci; fragptr.p->maxGciCompletedInLcp = cnewestCompletedGci; sendAccContOp(signal); /* START OPERATIONS IN ACC */ moveAccActiveFrag(signal); /* MOVE FROM ACC BLOCKED LIST TO ACTIVE LIST ON FRAGMENT */ } /*---------------*/ /* ELSE */ /*-------------------------------------------------------------------------*/ /* THE LOCAL CHECKPOINT HAS NOT BEEN STARTED. EXIT AND WAIT FOR * MORE SIGNALS */ /*-------------------------------------------------------------------------*/ /* DO NOTHING, EXIT IS EXECUTED BELOW */ /*-------------------------------------------------------------------------*/ return; }//Dblqh::lcpStartedLab() /*--------------------------------------------------------------------------- * ACC HAVE RESTARTED THE BLOCKED OPERATIONS AGAIN IN ONE FRAGMENT PART. * IT IS NOW OUR TURN TO RESTART ALL OPERATIONS QUEUED IN LQH IF ALL * FRAGMENT PARTS ARE COMPLETED. *-------------------------------------------------------------------------- */ void Dblqh::execACC_CONTOPCONF(Signal* signal) { if(ERROR_INSERTED(5035) && signal->getSendersBlockRef() != reference()){ sendSignalWithDelay(reference(), GSN_ACC_CONTOPCONF, signal, 1000, signal->length()); return; } jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); lcpLocptr.p->accContCounter = 1; lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (lcpLocptr.p->accContCounter == 0) { jam(); return; }//if lcpLocptr.i = lcpLocptr.p->nextLcpLoc; } while (lcpLocptr.i != RNIL); fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); restartOperationsLab(signal); return; }//Dblqh::execACC_CONTOPCONF() /* ********************************************************* */ /* LQH_RESTART_OP: Restart operations after beeing blocked. */ /* ********************************************************* */ /*---------------------------------------------------------------------------*/ /* PRECONDITION: FRAG_STATUS = BLOCKED AND LCP_STATE = STARTED */ /*---------------------------------------------------------------------------*/ void Dblqh::execLQH_RESTART_OP(Signal* signal) { jamEntry(); fragptr.i = signal->theData[0]; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); lcpPtr.i = signal->theData[1]; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(fragptr.p->fragStatus == Fragrecord::BLOCKED); if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) { jam(); /***********************************************************************/ /* THIS SIGNAL CAN ONLY BE RECEIVED WHEN FRAGMENT IS BLOCKED AND * THE LOCAL CHECKPOINT HAS BEEN STARTED. THE BLOCKING WILL BE * REMOVED AS SOON AS ALL OPERATIONS HAVE BEEN STARTED. ***********************************************************************/ restartOperationsLab(signal); } else if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) { jam(); /*******************************************************************> * THE CHECKPOINT IS COMPLETED BUT HAS NOT YET STARTED UP * ALL OPERATIONS AGAIN. * WE PERFORM THIS START-UP BEFORE CONTINUING WITH THE NEXT * FRAGMENT OF THE LOCAL CHECKPOINT TO AVOID ANY STRANGE ERRORS. *******************************************************************> */ restartOperationsLab(signal); } else { ndbrequire(false); } }//Dblqh::execLQH_RESTART_OP() void Dblqh::restartOperationsLab(Signal* signal) { Uint32 loopCount = 0; tcConnectptr.i = fragptr.p->firstWaitQueue; do { if (tcConnectptr.i != RNIL) { jam(); /*---------------------------------------------------------------------------*/ /* START UP THE TRANSACTION AGAIN. WE START IT AS A SEPARATE SIGNAL. */ /*---------------------------------------------------------------------------*/ signal->theData[0] = ZRESTART_OPERATIONS_AFTER_STOP; signal->theData[1] = tcConnectptr.i; signal->theData[2] = fragptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); tcConnectptr.i = tcConnectptr.p->nextTc; } else { jam(); /*--------------------------------------------------------------------------*/ /* NO MORE OPERATIONS TO RESTART. WE CAN NOW RESET THE STATE TO ACTIVE AND */ /* RESTART NORMAL ACTIVITIES ON THE FRAGMENT WHILE THE FUZZY PART OF THE */ /* LOCAL CHECKPOINT IS COMPLETING. */ /* IF THE CHECKPOINT WAS COMPLETED ALREADY ON THIS FRAGMENT WE PROCEED WITH */ /* THE NEXT FRAGMENT NOW THAT WE HAVE COMPLETED THIS CHECKPOINT. */ /*--------------------------------------------------------------------------*/ fragptr.p->fragStatus = Fragrecord::FSACTIVE; if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) { jam(); contChkpNextFragLab(signal); return; }//if return; }//if loopCount++; if (loopCount > 16) { jam(); signal->theData[0] = fragptr.i; signal->theData[1] = lcpPtr.i; sendSignal(cownref, GSN_LQH_RESTART_OP, signal, 2, JBB); return; }//if } while (1); }//Dblqh::restartOperationsLab() void Dblqh::restartOperationsAfterStopLab(Signal* signal) { /*------------------------------------------------------------------------- * WHEN ARRIVING HERE THE OPERATION IS ALREADY SET IN THE ACTIVE LIST. * THUS WE CAN IMMEDIATELY CALL THE METHODS THAT EXECUTE FROM WHERE * THE OPERATION WAS STOPPED. *------------------------------------------------------------------------ */ switch (tcConnectptr.p->transactionState) { case TcConnectionrec::STOPPED: jam(); /*----------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND ACCKEYREQ *---------------------------------------------------------------------- */ prepareContinueAfterBlockedLab(signal); return; break; case TcConnectionrec::COMMIT_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND ACC_COMMITREQ * --------------------------------------------------------------------- */ releaseActiveFrag(signal); commitContinueAfterBlockedLab(signal); return; break; case TcConnectionrec::ABORT_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND ACC_ABORTREQ * --------------------------------------------------------------------- */ abortContinueAfterBlockedLab(signal, true); return; break; case TcConnectionrec::COPY_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT * --------------------------------------------------------------------- */ continueCopyAfterBlockedLab(signal); return; break; case TcConnectionrec::COPY_FIRST_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT * --------------------------------------------------------------------- */ continueFirstCopyAfterBlockedLab(signal); return; break; case TcConnectionrec::SCAN_FIRST_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN * --------------------------------------------------------------------- */ tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; continueFirstScanAfterBlockedLab(signal); return; break; case TcConnectionrec::SCAN_CHECK_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN * --------------------------------------------------------------------- */ tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; continueAfterCheckLcpStopBlocked(signal); return; break; case TcConnectionrec::SCAN_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN * --------------------------------------------------------------------- */ tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; continueScanAfterBlockedLab(signal); return; break; case TcConnectionrec::SCAN_RELEASE_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING RELEASE * LOCKS IN SCAN * --------------------------------------------------------------------- */ tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; continueScanReleaseAfterBlockedLab(signal); return; break; case TcConnectionrec::SCAN_CLOSE_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF SCAN * --------------------------------------------------------------------- */ continueCloseScanAfterBlockedLab(signal); return; break; case TcConnectionrec::COPY_CLOSE_STOPPED: jam(); /* ---------------------------------------------------------------------- * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF COPY * --------------------------------------------------------------------- */ continueCloseCopyAfterBlockedLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch }//Dblqh::restartOperationsAfterStopLab() /* *************** */ /* ACC_LCPCONF > */ /* *************** */ /*--------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = ACC_STARTED *-------------------------------------------------------------------------- */ void Dblqh::execACC_LCPCONF(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN * THIS REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A * SYSTEM RESTART. * ----------------------------------------------------------------------- */ lcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_COMPLETED; lcpCompletedLab(signal); return; }//Dblqh::execACC_LCPCONF() /* *************** */ /* TUP_LCPCONF > */ /* *************** */ /* -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = TUP_STARTED * ------------------------------------------------------------------------- */ void Dblqh::execTUP_LCPCONF(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_STARTED); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ----------------------------------------------------------------------- */ lcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_COMPLETED; lcpCompletedLab(signal); return; }//Dblqh::execTUP_LCPCONF() void Dblqh::lcpCompletedLab(Signal* signal) { checkLcpCompleted(signal); if (lcpPtr.p->lcpState != LcpRecord::LCP_COMPLETED) { jam(); /* ---------------------------------------------------------------------- * THE LOCAL CHECKPOINT HAS NOT BEEN COMPLETED, EXIT & WAIT * FOR MORE SIGNALS * --------------------------------------------------------------------- */ return; }//if /* ------------------------------------------------------------------------ * THE LOCAL CHECKPOINT HAS BEEN COMPLETED. IT IS NOW TIME TO START * A LOCAL CHECKPOINT ON THE NEXT FRAGMENT OR COMPLETE THIS LCP ROUND. * ------------------------------------------------------------------------ * WE START BY SENDING LCP_REPORT TO DIH TO REPORT THE COMPLETED LCP. * TO CATER FOR NODE CRASHES WE SEND IT IN PARALLEL TO ALL NODES. * ----------------------------------------------------------------------- */ fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->fragActiveStatus = ZFALSE; contChkpNextFragLab(signal); return; }//Dblqh::lcpCompletedLab() void Dblqh::sendLCP_FRAG_REP(Signal * signal, const LcpRecord::FragOrd & fragOrd) const { FragrecordPtr fragPtr; fragPtr.i = fragOrd.fragPtrI; ptrCheckGuard(fragPtr, cfragrecFileSize, fragrecord); ndbrequire(fragOrd.lcpFragOrd.lcpNo < MAX_LCP_STORED); LcpFragRep * const lcpReport = (LcpFragRep *)&signal->theData[0]; lcpReport->nodeId = cownNodeid; lcpReport->lcpId = fragOrd.lcpFragOrd.lcpId; lcpReport->lcpNo = fragOrd.lcpFragOrd.lcpNo; lcpReport->tableId = fragOrd.lcpFragOrd.tableId; lcpReport->fragId = fragOrd.lcpFragOrd.fragmentId; lcpReport->maxGciCompleted = fragPtr.p->maxGciCompletedInLcp; lcpReport->maxGciStarted = fragPtr.p->maxGciInLcp; for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); Uint32 nodeId = cnodeData[i]; if(cnodeStatus[i] == ZNODE_UP){ jam(); BlockReference Tblockref = calcDihBlockRef(nodeId); sendSignal(Tblockref, GSN_LCP_FRAG_REP, signal, LcpFragRep::SignalLength, JBB); }//if }//for } void Dblqh::contChkpNextFragLab(Signal* signal) { /* ------------------------------------------------------------------------ * UPDATE THE LATEST LOCAL CHECKPOINT COMPLETED ON FRAGMENT. * UPDATE THE LCP_ID OF THIS CHECKPOINT. * REMOVE THE LINK BETWEEN THE FRAGMENT RECORD AND THE LCP RECORD. * ----------------------------------------------------------------------- */ if (fragptr.p->fragStatus == Fragrecord::BLOCKED) { jam(); /** * LCP of fragment complete * but restarting of operations isn't */ lcpPtr.p->lcpState = LcpRecord::LCP_BLOCKED_COMP; //restartOperationsLab(signal); return; }//if /** * Send rep when fragment is done + unblocked */ sendLCP_FRAG_REP(signal, lcpPtr.p->currentFragment); /* ------------------------------------------------------------------------ * WE ALSO RELEASE THE LOCAL LCP RECORDS. * ----------------------------------------------------------------------- */ releaseLocalLcps(signal); if (lcpPtr.p->lcpQueued) { jam(); /* ---------------------------------------------------------------------- * Transfer the state from the queued to the active LCP. * --------------------------------------------------------------------- */ lcpPtr.p->lcpQueued = false; lcpPtr.p->currentFragment = lcpPtr.p->queuedFragment; /* ---------------------------------------------------------------------- * START THE QUEUED LOCAL CHECKPOINT. * --------------------------------------------------------------------- */ sendLCP_FRAGIDREQ(signal); return; }//if lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; if (lcpPtr.p->lastFragmentFlag){ jam(); /* ---------------------------------------------------------------------- * NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED. * --------------------------------------------------------------------- */ completeLcpRoundLab(signal); return; }//if if (lcpPtr.p->reportEmpty) { jam(); sendEMPTY_LCP_CONF(signal, false); }//if return; }//Dblqh::contChkpNextFragLab() void Dblqh::sendLCP_FRAGIDREQ(Signal* signal) { ndbrequire(lcpPtr.p->firstLcpLocTup == RNIL); ndbrequire(lcpPtr.p->firstLcpLocAcc == RNIL); TablerecPtr tabPtr; tabPtr.i = lcpPtr.p->currentFragment.lcpFragOrd.tableId; ptrAss(tabPtr, tablerec); if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ jam(); /** * Fake that the fragment is done */ lcpCompletedLab(signal); return; } ndbrequire(tabPtr.p->tableStatus == Tablerec::TABLE_DEFINED); lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_FRAGID; signal->theData[0] = lcpPtr.i; signal->theData[1] = cownref; signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; signal->theData[5] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; sendSignal(fragptr.p->accBlockref, GSN_LCP_FRAGIDREQ, signal, 6, JBB); }//Dblqh::sendLCP_FRAGIDREQ() void Dblqh::sendEMPTY_LCP_CONF(Signal* signal, bool idle) { EmptyLcpConf * const rep = (EmptyLcpConf*)&signal->theData[0]; /* ---------------------------------------------------------------------- * We have been requested to report when there are no more local * waiting to be started or ongoing. In this signal we also report * the last completed fragments state. * ---------------------------------------------------------------------- */ rep->senderNodeId = getOwnNodeId(); if(!idle){ jam(); rep->idle = 0 ; rep->tableId = lcpPtr.p->currentFragment.lcpFragOrd.tableId; rep->fragmentId = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; rep->lcpNo = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; rep->lcpId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId; } else { jam(); rep->idle = 1; rep->tableId = ~0; rep->fragmentId = ~0; rep->lcpNo = ~0; rep->lcpId = c_lcpId; } for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); Uint32 nodeId = cnodeData[i]; if (lcpPtr.p->m_EMPTY_LCP_REQ.get(nodeId)) { jam(); BlockReference blockref = calcDihBlockRef(nodeId); sendSignal(blockref, GSN_EMPTY_LCP_CONF, signal, EmptyLcpConf::SignalLength, JBB); }//if }//for lcpPtr.p->reportEmpty = false; lcpPtr.p->m_EMPTY_LCP_REQ.clear(); }//Dblqh::sendEMPTY_LCPCONF() void Dblqh::execACC_LCPREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execACC_LCPREF() void Dblqh::execTUP_LCPREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execTUP_LCPREF() /* -------------------------------------------------------------------------- * THE LOCAL CHECKPOINT ROUND IS NOW COMPLETED. SEND COMPLETED MESSAGE * TO THE MASTER DIH. * ------------------------------------------------------------------------- */ void Dblqh::completeLcpRoundLab(Signal* signal) { clcpCompletedState = LCP_CLOSE_STARTED; signal->theData[0] = caccBlockref; signal->theData[1] = cownref; sendSignal(caccBlockref, GSN_END_LCPREQ, signal, 2, JBB); signal->theData[0] = ctupBlockref; signal->theData[1] = cownref; sendSignal(ctupBlockref, GSN_END_LCPREQ, signal, 2, JBB); return; }//Dblqh::completeLcpRoundLab() void Dblqh::execEND_LCPCONF(Signal* signal) { jamEntry(); BlockReference userpointer = signal->theData[0]; if (userpointer == caccBlockref) { if (clcpCompletedState == LCP_CLOSE_STARTED) { jam(); clcpCompletedState = ACC_LCP_CLOSE_COMPLETED; return; } else { jam(); ndbrequire(clcpCompletedState == TUP_LCP_CLOSE_COMPLETED); clcpCompletedState = LCP_IDLE; }//if } else { ndbrequire(userpointer == ctupBlockref); if (clcpCompletedState == LCP_CLOSE_STARTED) { jam(); clcpCompletedState = TUP_LCP_CLOSE_COMPLETED; return; } else { jam(); ndbrequire(clcpCompletedState == ACC_LCP_CLOSE_COMPLETED); clcpCompletedState = LCP_IDLE; }//if }//if lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); sendLCP_COMPLETE_REP(signal, lcpPtr.p->currentFragment.lcpFragOrd.lcpId); }//Dblqh::execEND_LCPCONF() void Dblqh::sendLCP_COMPLETE_REP(Signal* signal, Uint32 lcpId) { cnoOfFragsCheckpointed = 0; ndbrequire((cnoOfNodes - 1) < (MAX_NDB_NODES - 1)); /* ------------------------------------------------------------------------ * WE SEND COMP_LCP_ROUND TO ALL NODES TO PREPARE FOR NODE CRASHES. * ----------------------------------------------------------------------- */ lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); lcpPtr.p->lastFragmentFlag = false; LcpCompleteRep* rep = (LcpCompleteRep*)signal->getDataPtrSend(); rep->nodeId = getOwnNodeId(); rep->lcpId = lcpId; rep->blockNo = DBLQH; for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); Uint32 nodeId = cnodeData[i]; if(cnodeStatus[i] == ZNODE_UP){ jam(); BlockReference blockref = calcDihBlockRef(nodeId); sendSignal(blockref, GSN_LCP_COMPLETE_REP, signal, LcpCompleteRep::SignalLength, JBB); }//if }//for if(lcpPtr.p->reportEmpty){ jam(); sendEMPTY_LCP_CONF(signal, true); } return; }//Dblqh::sendCOMP_LCP_ROUND() /* ========================================================================== * ======= CHECK IF ALL PARTS OF A LOCAL CHECKPOINT ARE COMPLETED ======= * * SUBROUTINE SHORT NAME = CLC * ========================================================================= */ void Dblqh::checkLcpCompleted(Signal* signal) { LcpLocRecordPtr clcLcpLocptr; clcLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; while (clcLcpLocptr.i != RNIL) { ptrCheckGuard(clcLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clcLcpLocptr.p->lcpLocstate != LcpLocRecord::ACC_COMPLETED) { jam(); ndbrequire((clcLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED) || (clcLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED)); return; }//if clcLcpLocptr.i = clcLcpLocptr.p->nextLcpLoc; } clcLcpLocptr.i = lcpPtr.p->firstLcpLocTup; while (clcLcpLocptr.i != RNIL){ ptrCheckGuard(clcLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clcLcpLocptr.p->lcpLocstate != LcpLocRecord::TUP_COMPLETED) { jam(); ndbrequire((clcLcpLocptr.p->lcpLocstate==LcpLocRecord::TUP_WAIT_STARTED) ||(clcLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_STARTED)); return; }//if clcLcpLocptr.i = clcLcpLocptr.p->nextLcpLoc; } lcpPtr.p->lcpState = LcpRecord::LCP_COMPLETED; }//Dblqh::checkLcpCompleted() /* ========================================================================== * ======= CHECK IF ALL HOLD OPERATIONS ARE COMPLETED ======= * * SUBROUTINE SHORT NAME = CHO * ========================================================================= */ void Dblqh::checkLcpHoldop(Signal* signal) { LcpLocRecordPtr choLcpLocptr; choLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { ptrCheckGuard(choLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (choLcpLocptr.p->lcpLocstate != LcpLocRecord::HOLDOP_READY) { ndbrequire(choLcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_LCPHOLDOP); return; }//if choLcpLocptr.i = choLcpLocptr.p->nextLcpLoc; } while (choLcpLocptr.i != RNIL); lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_ACTIVE_FINISH; }//Dblqh::checkLcpHoldop() /* ========================================================================== * ======= CHECK IF ALL PARTS OF A LOCAL CHECKPOINT ARE STARTED ======= * * SUBROUTINE SHORT NAME = CLS * ========================================================================== */ void Dblqh::checkLcpStarted(Signal* signal) { LcpLocRecordPtr clsLcpLocptr; terrorCode = ZOK; clsLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; int i = 0; do { ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED){ return; }//if clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; i++; } while (clsLcpLocptr.i != RNIL); i = 0; clsLcpLocptr.i = lcpPtr.p->firstLcpLocTup; do { ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED){ return; }//if clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; i++; } while (clsLcpLocptr.i != RNIL); lcpPtr.p->lcpState = LcpRecord::LCP_STARTED; }//Dblqh::checkLcpStarted() /* ========================================================================== * ======= CHECK IF ALL PREPARE TUP OPERATIONS ARE COMPLETED ======= * * SUBROUTINE SHORT NAME = CLT * ========================================================================== */ void Dblqh::checkLcpTupprep(Signal* signal) { LcpLocRecordPtr cltLcpLocptr; cltLcpLocptr.i = lcpPtr.p->firstLcpLocTup; do { ptrCheckGuard(cltLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (cltLcpLocptr.p->lcpLocstate != LcpLocRecord::IDLE) { ndbrequire(cltLcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_TUP_PREPLCP); return; }//if cltLcpLocptr.i = cltLcpLocptr.p->nextLcpLoc; } while (cltLcpLocptr.i != RNIL); lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_HOLDOPS; }//Dblqh::checkLcpTupprep() /* ========================================================================== * ======= INITIATE LCP LOCAL RECORD USED TOWARDS ACC ======= * * ========================================================================== */ void Dblqh::initLcpLocAcc(Signal* signal, Uint32 fragId) { lcpLocptr.p->nextLcpLoc = lcpPtr.p->firstLcpLocAcc; lcpPtr.p->firstLcpLocAcc = lcpLocptr.i; lcpLocptr.p->locFragid = fragId; lcpLocptr.p->waitingBlock = LcpLocRecord::ACC; lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; lcpLocptr.p->masterLcpRec = lcpPtr.i; lcpLocptr.p->tupRef = RNIL; }//Dblqh::initLcpLocAcc() /* ========================================================================== * ======= INITIATE LCP LOCAL RECORD USED TOWARDS TUP ======= * * ========================================================================== */ void Dblqh::initLcpLocTup(Signal* signal, Uint32 fragId) { lcpLocptr.p->nextLcpLoc = lcpPtr.p->firstLcpLocTup; lcpPtr.p->firstLcpLocTup = lcpLocptr.i; lcpLocptr.p->locFragid = fragId; lcpLocptr.p->waitingBlock = LcpLocRecord::TUP; lcpLocptr.p->lcpLocstate = LcpLocRecord::WAIT_TUP_PREPLCP; lcpLocptr.p->masterLcpRec = lcpPtr.i; lcpLocptr.p->tupRef = RNIL; }//Dblqh::initLcpLocTup() /* -------------------------------------------------------------------------- * ------- MOVE OPERATION FROM ACC WAITING LIST ON FRAGMENT ------- * ------- TO ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME = MAA * -------------------------------------------------------------------------- */ void Dblqh::moveAccActiveFrag(Signal* signal) { UintR maaTcNextConnectptr; tcConnectptr.i = fragptr.p->accBlockedList; fragptr.p->accBlockedList = RNIL; /* ------------------------------------------------------------------------ * WE WILL MOVE ALL RECORDS FROM THE ACC BLOCKED LIST AT ONCE. * ------------------------------------------------------------------------ */ while (tcConnectptr.i != RNIL) { jam(); ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); maaTcNextConnectptr = tcConnectptr.p->nextTc; ndbrequire(tcConnectptr.p->listState == TcConnectionrec::ACC_BLOCK_LIST); tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; linkActiveFrag(signal); tcConnectptr.i = maaTcNextConnectptr; }//while }//Dblqh::moveAccActiveFrag() /* -------------------------------------------------------------------------- * ------- MOVE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- * ------- TO ACC BLOCKED LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME = MAT * -------------------------------------------------------------------------- */ void Dblqh::moveActiveToAcc(Signal* signal) { TcConnectionrecPtr matTcNextConnectptr; releaseActiveList(signal); /* ------------------------------------------------------------------------ * PUT OPERATION RECORD FIRST IN ACC BLOCKED LIST. * ------------------------------------------------------------------------ */ matTcNextConnectptr.i = fragptr.p->accBlockedList; tcConnectptr.p->nextTc = matTcNextConnectptr.i; tcConnectptr.p->prevTc = RNIL; tcConnectptr.p->listState = TcConnectionrec::ACC_BLOCK_LIST; fragptr.p->accBlockedList = tcConnectptr.i; if (matTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(matTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); matTcNextConnectptr.p->prevTc = tcConnectptr.i; }//if }//Dblqh::moveActiveToAcc() /* ------------------------------------------------------------------------- */ /* ---- RELEASE LOCAL LCP RECORDS AFTER COMPLETION OF A LOCAL CHECKPOINT---- */ /* */ /* SUBROUTINE SHORT NAME = RLL */ /* ------------------------------------------------------------------------- */ void Dblqh::releaseLocalLcps(Signal* signal) { lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; while (lcpLocptr.i != RNIL){ ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); Uint32 tmp = lcpLocptr.p->nextLcpLoc; releaseLcpLoc(signal); lcpLocptr.i = tmp; } lcpPtr.p->firstLcpLocAcc = RNIL; lcpLocptr.i = lcpPtr.p->firstLcpLocTup; while (lcpLocptr.i != RNIL){ ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); Uint32 tmp = lcpLocptr.p->nextLcpLoc; releaseLcpLoc(signal); lcpLocptr.i = tmp; } lcpPtr.p->firstLcpLocTup = RNIL; }//Dblqh::releaseLocalLcps() /* ------------------------------------------------------------------------- */ /* ------- SEIZE LCP LOCAL RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::seizeLcpLoc(Signal* signal) { lcpLocptr.i = cfirstfreeLcpLoc; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); cfirstfreeLcpLoc = lcpLocptr.p->nextLcpLoc; lcpLocptr.p->nextLcpLoc = RNIL; }//Dblqh::seizeLcpLoc() /* ------------------------------------------------------------------------- */ /* ------- SEND ACC_CONT_OP ------- */ /* */ /* INPUT: LCP_PTR LOCAL CHECKPOINT RECORD */ /* FRAGPTR FRAGMENT RECORD */ /* */ /* SUBROUTINE SHORT NAME = SAC */ /* ------------------------------------------------------------------------- */ void Dblqh::sendAccContOp(Signal* signal) { LcpLocRecordPtr sacLcpLocptr; int count = 0; sacLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { ptrCheckGuard(sacLcpLocptr, clcpLocrecFileSize, lcpLocRecord); sacLcpLocptr.p->accContCounter = 0; if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED){ /* ------------------------------------------------------------------- */ /*SEND START OPERATIONS TO ACC AGAIN */ /* ------------------------------------------------------------------- */ signal->theData[0] = lcpPtr.p->lcpAccptr; signal->theData[1] = sacLcpLocptr.p->locFragid; sendSignal(fragptr.p->accBlockref, GSN_ACC_CONTOPREQ, signal, 2, JBA); count++; } else if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_COMPLETED){ signal->theData[0] = sacLcpLocptr.i; sendSignal(reference(), GSN_ACC_CONTOPCONF, signal, 1, JBB); } else { ndbrequire(false); } sacLcpLocptr.i = sacLcpLocptr.p->nextLcpLoc; } while (sacLcpLocptr.i != RNIL); }//Dblqh::sendAccContOp() /* ------------------------------------------------------------------------- */ /* ------- SEND ACC_LCPREQ AND TUP_LCPREQ ------- */ /* */ /* INPUT: LCP_PTR LOCAL CHECKPOINT RECORD */ /* FRAGPTR FRAGMENT RECORD */ /* SUBROUTINE SHORT NAME = STL */ /* ------------------------------------------------------------------------- */ void Dblqh::sendStartLcp(Signal* signal) { LcpLocRecordPtr stlLcpLocptr; stlLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { jam(); ptrCheckGuard(stlLcpLocptr, clcpLocrecFileSize, lcpLocRecord); stlLcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_WAIT_STARTED; signal->theData[0] = lcpPtr.p->lcpAccptr; signal->theData[1] = stlLcpLocptr.i; signal->theData[2] = stlLcpLocptr.p->locFragid; sendSignal(fragptr.p->accBlockref, GSN_ACC_LCPREQ, signal, 3, JBA); stlLcpLocptr.i = stlLcpLocptr.p->nextLcpLoc; } while (stlLcpLocptr.i != RNIL); stlLcpLocptr.i = lcpPtr.p->firstLcpLocTup; do { jam(); ptrCheckGuard(stlLcpLocptr, clcpLocrecFileSize, lcpLocRecord); stlLcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_WAIT_STARTED; signal->theData[0] = stlLcpLocptr.i; signal->theData[1] = cownref; signal->theData[2] = stlLcpLocptr.p->tupRef; sendSignal(fragptr.p->tupBlockref, GSN_TUP_LCPREQ, signal, 3, JBA); stlLcpLocptr.i = stlLcpLocptr.p->nextLcpLoc; } while (stlLcpLocptr.i != RNIL); }//Dblqh::sendStartLcp() /* ------------------------------------------------------------------------- */ /* ------- SET THE LOG TAIL IN THE LOG FILES ------- */ /* */ /*THIS SUBROUTINE HAVE BEEN BUGGY AND IS RATHER COMPLEX. IT IS IMPORTANT TO */ /*REMEMBER THAT WE SEARCH FROM THE TAIL UNTIL WE REACH THE HEAD (CURRENT). */ /*THE TAIL AND HEAD CAN BE ON THE SAME MBYTE. WE SEARCH UNTIL WE FIND A MBYTE*/ /*THAT WE NEED TO KEEP. WE THEN SET THE TAIL TO BE THE PREVIOUS. IF WE DO */ /*NOT FIND A MBYTE THAT WE NEED TO KEEP UNTIL WE REACH THE HEAD THEN WE USE */ /*THE HEAD AS TAIL. FINALLY WE HAVE TO MOVE BACK THE TAIL TO ALSO INCLUDE */ /*ALL PREPARE RECORDS. THIS MEANS THAT LONG-LIVED TRANSACTIONS ARE DANGEROUS */ /*FOR SHORT LOGS. */ /* ------------------------------------------------------------------------- */ // this function has not been verified yet Uint32 Dblqh::remainingLogSize(const LogFileRecordPtr &sltCurrLogFilePtr, const LogPartRecordPtr &sltLogPartPtr) { Uint32 hf = sltCurrLogFilePtr.p->fileNo*ZNO_MBYTES_IN_FILE+sltCurrLogFilePtr.p->currentMbyte; Uint32 tf = sltLogPartPtr.p->logTailFileNo*ZNO_MBYTES_IN_FILE+sltLogPartPtr.p->logTailMbyte; Uint32 sz = sltLogPartPtr.p->noLogFiles*ZNO_MBYTES_IN_FILE; if (tf > hf) hf += sz; return sz-(hf-tf); } void Dblqh::setLogTail(Signal* signal, Uint32 keepGci) { LogPartRecordPtr sltLogPartPtr; LogFileRecordPtr sltLogFilePtr; #if 0 LogFileRecordPtr sltCurrLogFilePtr; #endif UintR tsltMbyte; UintR tsltStartMbyte; UintR tsltIndex; UintR tsltFlag; for (sltLogPartPtr.i = 0; sltLogPartPtr.i < 4; sltLogPartPtr.i++) { jam(); ptrAss(sltLogPartPtr, logPartRecord); findLogfile(signal, sltLogPartPtr.p->logTailFileNo, sltLogPartPtr, &sltLogFilePtr); #if 0 sltCurrLogFilePtr.i = sltLogPartPtr.p->currentLogfile; ptrCheckGuard(sltCurrLogFilePtr, clogFileFileSize, logFileRecord); infoEvent("setLogTail: Available log file %d size = %d[mbytes]+%d[words]", sltLogPartPtr.i, remainingLogSize(sltCurrLogFilePtr, sltLogPartPtr), sltCurrLogFilePtr.p->remainingWordsInMbyte); #endif tsltMbyte = sltLogPartPtr.p->logTailMbyte; tsltStartMbyte = tsltMbyte; tsltFlag = ZFALSE; if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) { /* ------------------------------------------------------------------------- */ /*THE LOG AND THE TAIL IS ALREADY IN THE SAME FILE. */ /* ------------------------------------------------------------------------- */ if (sltLogFilePtr.p->currentMbyte >= sltLogPartPtr.p->logTailMbyte) { jam(); /* ------------------------------------------------------------------------- */ /*THE CURRENT MBYTE IS AHEAD OF OR AT THE TAIL. THUS WE WILL ONLY LOOK FOR */ /*THE TAIL UNTIL WE REACH THE CURRENT MBYTE WHICH IS IN THIS LOG FILE. */ /*IF THE LOG TAIL IS AHEAD OF THE CURRENT MBYTE BUT IN THE SAME LOG FILE */ /*THEN WE HAVE TO SEARCH THROUGH ALL FILES BEFORE WE COME TO THE CURRENT */ /*MBYTE. WE ALWAYS STOP WHEN WE COME TO THE CURRENT MBYTE SINCE THE TAIL */ /*CAN NEVER BE BEFORE THE HEAD. */ /* ------------------------------------------------------------------------- */ tsltFlag = ZTRUE; }//if }//if /* ------------------------------------------------------------------------- */ /*NOW START SEARCHING FOR THE NEW TAIL, STARTING AT THE CURRENT TAIL AND */ /*PROCEEDING UNTIL WE FIND A MBYTE WHICH IS NEEDED TO KEEP OR UNTIL WE REACH */ /*CURRENT MBYTE (THE HEAD). */ /* ------------------------------------------------------------------------- */ SLT_LOOP: for (tsltIndex = tsltStartMbyte; tsltIndex <= ZNO_MBYTES_IN_FILE - 1; tsltIndex++) { if (sltLogFilePtr.p->logMaxGciStarted[tsltIndex] >= keepGci) { /* ------------------------------------------------------------------------- */ /*WE ARE NOT ALLOWED TO STEP THE LOG ANY FURTHER AHEAD */ /*SET THE NEW LOG TAIL AND CONTINUE WITH NEXT LOG PART. */ /*THIS MBYTE IS NOT TO BE INCLUDED SO WE NEED TO STEP BACK ONE MBYTE. */ /* ------------------------------------------------------------------------- */ if (tsltIndex != 0) { jam(); tsltMbyte = tsltIndex - 1; } else { jam(); /* ------------------------------------------------------------------------- */ /*STEPPING BACK INCLUDES ALSO STEPPING BACK TO THE PREVIOUS LOG FILE. */ /* ------------------------------------------------------------------------- */ tsltMbyte = ZNO_MBYTES_IN_FILE - 1; sltLogFilePtr.i = sltLogFilePtr.p->prevLogFile; ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord); }//if goto SLT_BREAK; } else { jam(); if (tsltFlag == ZTRUE) { /* ------------------------------------------------------------------------- */ /*WE ARE IN THE SAME FILE AS THE CURRENT MBYTE AND WE CAN REACH THE CURRENT */ /*MBYTE BEFORE WE REACH A NEW TAIL. */ /* ------------------------------------------------------------------------- */ if (tsltIndex == sltLogFilePtr.p->currentMbyte) { jam(); /* ------------------------------------------------------------------------- */ /*THE TAIL OF THE LOG IS ACTUALLY WITHIN THE CURRENT MBYTE. THUS WE SET THE */ /*LOG TAIL TO BE THE CURRENT MBYTE. */ /* ------------------------------------------------------------------------- */ tsltMbyte = sltLogFilePtr.p->currentMbyte; goto SLT_BREAK; }//if }//if }//if }//for sltLogFilePtr.i = sltLogFilePtr.p->nextLogFile; ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord); if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) { jam(); tsltFlag = ZTRUE; }//if tsltStartMbyte = 0; goto SLT_LOOP; SLT_BREAK: jam(); { UintR ToldTailFileNo = sltLogPartPtr.p->logTailFileNo; UintR ToldTailMByte = sltLogPartPtr.p->logTailMbyte; arrGuard(tsltMbyte, 16); sltLogPartPtr.p->logTailFileNo = sltLogFilePtr.p->logLastPrepRef[tsltMbyte] >> 16; /* ------------------------------------------------------------------------- */ /*SINCE LOG_MAX_GCI_STARTED ONLY KEEP TRACK OF COMMIT LOG RECORDS WE ALSO */ /*HAVE TO STEP BACK THE TAIL SO THAT WE INCLUDE ALL PREPARE RECORDS */ /*NEEDED FOR THOSE COMMIT RECORDS IN THIS MBYTE. THIS IS A RATHER */ /*CONSERVATIVE APPROACH BUT IT WORKS. */ /* ------------------------------------------------------------------------- */ sltLogPartPtr.p->logTailMbyte = sltLogFilePtr.p->logLastPrepRef[tsltMbyte] & 65535; if ((ToldTailFileNo != sltLogPartPtr.p->logTailFileNo) || (ToldTailMByte != sltLogPartPtr.p->logTailMbyte)) { jam(); if (sltLogPartPtr.p->logPartState == LogPartRecord::TAIL_PROBLEM) { if (sltLogPartPtr.p->firstLogQueue == RNIL) { jam(); sltLogPartPtr.p->logPartState = LogPartRecord::IDLE; } else { jam(); sltLogPartPtr.p->logPartState = LogPartRecord::ACTIVE; }//if }//if }//if } #if 0 infoEvent("setLogTail: Available log file %d size = %d[mbytes]+%d[words]", sltLogPartPtr.i, remainingLogSize(sltCurrLogFilePtr, sltLogPartPtr), sltCurrLogFilePtr.p->remainingWordsInMbyte); #endif }//for }//Dblqh::setLogTail() /* ######################################################################### */ /* ####### GLOBAL CHECKPOINT MODULE ####### */ /* */ /* ######################################################################### */ /*---------------------------------------------------------------------------*/ /* THIS MODULE HELPS DIH IN DISCOVERING WHEN GLOBAL CHECKPOINTS ARE */ /* RECOVERABLE. IT HANDLES THE REQUEST GCP_SAVEREQ THAT REQUESTS LQH TO */ /* SAVE A PARTICULAR GLOBAL CHECKPOINT TO DISK AND RESPOND WHEN COMPLETED. */ /*---------------------------------------------------------------------------*/ /* *************** */ /* GCP_SAVEREQ > */ /* *************** */ void Dblqh::execGCP_SAVEREQ(Signal* signal) { jamEntry(); const GCPSaveReq * const saveReq = (GCPSaveReq *)&signal->theData[0]; if (ERROR_INSERTED(5000)) { systemErrorLab(signal); } if (ERROR_INSERTED(5007)){ CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_GCP_SAVEREQ, signal, 10000, signal->length()); return; } const Uint32 dihBlockRef = saveReq->dihBlockRef; const Uint32 dihPtr = saveReq->dihPtr; const Uint32 gci = saveReq->gci; ndbrequire(gci >= cnewestCompletedGci); if (gci == cnewestCompletedGci) { /*---------------------------------------------------------------------------*/ /* GLOBAL CHECKPOINT HAVE ALREADY BEEN HANDLED. REQUEST MUST HAVE BEEN SENT */ /* FROM NEW MASTER DIH. */ /*---------------------------------------------------------------------------*/ if (ccurrentGcprec == RNIL) { jam(); /*---------------------------------------------------------------------------*/ /* THIS INDICATES THAT WE HAVE ALREADY SENT GCP_SAVECONF TO PREVIOUS MASTER. */ /* WE SIMPLY SEND IT ALSO TO THE NEW MASTER. */ /*---------------------------------------------------------------------------*/ GCPSaveConf * const saveConf = (GCPSaveConf*)&signal->theData[0]; saveConf->dihPtr = dihPtr; saveConf->nodeId = getOwnNodeId(); saveConf->gci = cnewestCompletedGci; sendSignal(dihBlockRef, GSN_GCP_SAVECONF, signal, GCPSaveConf::SignalLength, JBA); return; } jam(); /*---------------------------------------------------------------------------*/ /* WE HAVE NOT YET SENT THE RESPONSE TO THE OLD MASTER. WE WILL SET THE NEW */ /* RECEIVER OF THE RESPONSE AND THEN EXIT SINCE THE PROCESS IS ALREADY */ /* STARTED. */ /*---------------------------------------------------------------------------*/ gcpPtr.i = ccurrentGcprec; ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); gcpPtr.p->gcpUserptr = dihPtr; gcpPtr.p->gcpBlockref = dihBlockRef; return; }//if ndbrequire(ccurrentGcprec == RNIL); if(getNodeState().startLevel >= NodeState::SL_STOPPING_4){ GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0]; saveRef->dihPtr = dihPtr; saveRef->nodeId = getOwnNodeId(); saveRef->gci = gci; saveRef->errorCode = GCPSaveRef::NodeShutdownInProgress; sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal, GCPSaveRef::SignalLength, JBB); return; } if(getNodeState().getNodeRestartInProgress()){ GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0]; saveRef->dihPtr = dihPtr; saveRef->nodeId = getOwnNodeId(); saveRef->gci = gci; saveRef->errorCode = GCPSaveRef::NodeRestartInProgress; sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal, GCPSaveRef::SignalLength, JBB); return; } ccurrentGcprec = 0; gcpPtr.i = ccurrentGcprec; ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); cnewestCompletedGci = gci; if (gci > cnewestGci) { jam(); cnewestGci = gci; }//if gcpPtr.p->gcpBlockref = dihBlockRef; gcpPtr.p->gcpUserptr = dihPtr; gcpPtr.p->gcpId = gci; bool tlogActive = false; for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { ptrAss(logPartPtr, logPartRecord); if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { jam(); logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_TRUE; tlogActive = true; } else { jam(); logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); writeCompletedGciLog(signal); }//if }//for if (tlogActive == true) { jam(); return; }//if initGcpRecLab(signal); startTimeSupervision(signal); return; }//Dblqh::execGCP_SAVEREQ() /* ------------------------------------------------------------------------- */ /* START TIME SUPERVISION OF THE LOG PARTS. */ /* ------------------------------------------------------------------------- */ void Dblqh::startTimeSupervision(Signal* signal) { for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* WE HAVE TO START CHECKING IF THE LOG IS TO BE WRITTEN EVEN IF PAGES ARE */ /* FULL. INITIALISE THE VALUES OF WHERE WE ARE IN THE LOG CURRENTLY. */ /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ logPartPtr.p->logPartTimer = 0; logPartPtr.p->logTimer = 1; signal->theData[0] = ZTIME_SUPERVISION; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//for }//Dblqh::startTimeSupervision() /*---------------------------------------------------------------------------*/ /* WE SET THE GLOBAL CHECKPOINT VARIABLES AFTER WRITING THE COMPLETED GCI LOG*/ /* RECORD. THIS ENSURES THAT WE WILL ENCOUNTER THE COMPLETED GCI RECORD WHEN */ /* WE EXECUTE THE FRAGMENT LOG. */ /*---------------------------------------------------------------------------*/ void Dblqh::initGcpRecLab(Signal* signal) { /* ======================================================================== */ /* ======= INITIATE GCP RECORD ======= */ /* */ /* SUBROUTINE SHORT NAME = IGR */ /* ======================================================================== */ for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); /*--------------------------------------------------*/ /* BY SETTING THE GCPREC = 0 WE START THE */ /* CHECKING BY CHECK_GCP_COMPLETED. THIS */ /* CHECKING MUST NOT BE STARTED UNTIL WE HAVE */ /* INSERTED ALL COMPLETE GCI LOG RECORDS IN */ /* ALL LOG PARTS. */ /*--------------------------------------------------*/ logPartPtr.p->gcprec = 0; gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZWAIT_DISK; gcpPtr.p->gcpSyncReady[logPartPtr.i] = ZFALSE; logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); gcpPtr.p->gcpFilePtr[logPartPtr.i] = logFilePtr.i; logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) { jam(); /*--------------------------------------------------*/ /* SINCE THE CURRENT FILEPAGE POINTS AT THE */ /* NEXT WORD TO BE WRITTEN WE HAVE TO ADJUST */ /* FOR THIS BY DECREASING THE FILE PAGE BY ONE*/ /* IF NO WORD HAS BEEN WRITTEN ON THE CURRENT */ /* FILEPAGE. */ /*--------------------------------------------------*/ gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage - 1; gcpPtr.p->gcpWordNo[logPartPtr.i] = ZPAGE_SIZE - 1; } else { jam(); gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage; gcpPtr.p->gcpWordNo[logPartPtr.i] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1; }//if }//for return; }//Dblqh::initGcpRecLab() /* ========================================================================= */ /* ==== CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED AFTER A COMPLETED===== */ /* DISK WRITE. */ /* */ /* SUBROUTINE SHORT NAME = CGC */ /* ========================================================================= */ void Dblqh::checkGcpCompleted(Signal* signal, Uint32 tcgcPageWritten, Uint32 tcgcWordWritten) { UintR tcgcFlag; UintR tcgcJ; gcpPtr.i = logPartPtr.p->gcprec; if (gcpPtr.i != RNIL) { jam(); /* ------------------------------------------------------------------------- */ /* IF THE GLOBAL CHECKPOINT IS NOT WAITING FOR COMPLETION THEN WE CAN QUIT */ /* THE SEARCH IMMEDIATELY. */ /* ------------------------------------------------------------------------- */ ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); if (gcpPtr.p->gcpFilePtr[logPartPtr.i] == logFilePtr.i) { /* ------------------------------------------------------------------------- */ /* IF THE COMPLETED DISK OPERATION WAS ON ANOTHER FILE THAN THE ONE WE ARE */ /* WAITING FOR, THEN WE CAN ALSO QUIT THE SEARCH IMMEDIATELY. */ /* ------------------------------------------------------------------------- */ if (tcgcPageWritten < gcpPtr.p->gcpPageNo[logPartPtr.i]) { jam(); /* ------------------------------------------------------------------------- */ /* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ /* ------------------------------------------------------------------------- */ return; } else { if (tcgcPageWritten == gcpPtr.p->gcpPageNo[logPartPtr.i]) { if (tcgcWordWritten < gcpPtr.p->gcpWordNo[logPartPtr.i]) { jam(); /* ------------------------------------------------------------------------- */ /* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ /* ------------------------------------------------------------------------- */ return; }//if }//if }//if /* ------------------------------------------------------------------------- */ /* THIS LOG PART HAVE WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ /* ------------------------------------------------------------------------- */ logPartPtr.p->gcprec = RNIL; gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZON_DISK; tcgcFlag = ZTRUE; for (tcgcJ = 0; tcgcJ <= 3; tcgcJ++) { jam(); if (gcpPtr.p->gcpLogPartState[tcgcJ] != ZON_DISK) { jam(); /* ------------------------------------------------------------------------- */ /*ALL LOG PARTS HAVE NOT SAVED THIS GLOBAL CHECKPOINT TO DISK YET. WAIT FOR */ /*THEM TO COMPLETE. */ /* ------------------------------------------------------------------------- */ tcgcFlag = ZFALSE; }//if }//for if (tcgcFlag == ZTRUE) { jam(); /* ------------------------------------------------------------------------- */ /*WE HAVE FOUND A COMPLETED GLOBAL CHECKPOINT OPERATION. WE NOW NEED TO SEND */ /*GCP_SAVECONF, REMOVE THE GCP RECORD FROM THE LIST OF WAITING GCP RECORDS */ /*ON THIS LOG PART AND RELEASE THE GCP RECORD. */ // After changing the log implementation we need to perform a FSSYNCREQ on all // log files where the last log word resided first before proceeding. /* ------------------------------------------------------------------------- */ UintR Ti; for (Ti = 0; Ti < 4; Ti++) { LogFileRecordPtr loopLogFilePtr; loopLogFilePtr.i = gcpPtr.p->gcpFilePtr[Ti]; ptrCheckGuard(loopLogFilePtr, clogFileFileSize, logFileRecord); if (loopLogFilePtr.p->logFileStatus == LogFileRecord::OPEN) { jam(); signal->theData[0] = loopLogFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = gcpPtr.p->gcpFilePtr[Ti]; sendSignal(NDBFS_REF, GSN_FSSYNCREQ, signal, 3, JBA); } else { ndbrequire((loopLogFilePtr.p->logFileStatus == LogFileRecord::CLOSED) || (loopLogFilePtr.p->logFileStatus == LogFileRecord::CLOSING_WRITE_LOG) || (loopLogFilePtr.p->logFileStatus == LogFileRecord::OPENING_WRITE_LOG)); signal->theData[0] = loopLogFilePtr.i; execFSSYNCCONF(signal); }//if }//for return; }//if }//if }//if }//Dblqh::checkGcpCompleted() void Dblqh::execFSSYNCCONF(Signal* signal) { GcpRecordPtr localGcpPtr; LogFileRecordPtr localLogFilePtr; LogPartRecordPtr localLogPartPtr; localLogFilePtr.i = signal->theData[0]; ptrCheckGuard(localLogFilePtr, clogFileFileSize, logFileRecord); localLogPartPtr.i = localLogFilePtr.p->logPartRec; localGcpPtr.i = ccurrentGcprec; ptrCheckGuard(localGcpPtr, cgcprecFileSize, gcpRecord); localGcpPtr.p->gcpSyncReady[localLogPartPtr.i] = ZTRUE; UintR Ti; for (Ti = 0; Ti < 4; Ti++) { jam(); if (localGcpPtr.p->gcpSyncReady[Ti] == ZFALSE) { jam(); return; }//if }//for GCPSaveConf * const saveConf = (GCPSaveConf *)&signal->theData[0]; saveConf->dihPtr = localGcpPtr.p->gcpUserptr; saveConf->nodeId = getOwnNodeId(); saveConf->gci = localGcpPtr.p->gcpId; sendSignal(localGcpPtr.p->gcpBlockref, GSN_GCP_SAVECONF, signal, GCPSaveConf::SignalLength, JBA); ccurrentGcprec = RNIL; }//Dblqh::execFSSYNCCONF() void Dblqh::execFSSYNCREF(Signal* signal) { jamEntry(); systemErrorLab(signal); return; }//Dblqh::execFSSYNCREF() /* ######################################################################### */ /* ####### FILE HANDLING MODULE ####### */ /* */ /* ######################################################################### */ /* THIS MODULE HANDLES RESPONSE MESSAGES FROM THE FILE SYSTEM */ /* ######################################################################### */ /* ######################################################################### */ /* SIGNAL RECEPTION MODULE */ /* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ /* */ /* THIS MODULE CHECKS THE STATE AND JUMPS TO THE PROPER PART OF THE FILE */ /* HANDLING MODULE. */ /* ######################################################################### */ /* *************** */ /* FSCLOSECONF > */ /* *************** */ void Dblqh::execFSCLOSECONF(Signal* signal) { jamEntry(); logFilePtr.i = signal->theData[0]; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); switch (logFilePtr.p->logFileStatus) { case LogFileRecord::CLOSE_SR_INVALIDATE_PAGES: jam(); logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; // Set the prev file to check if we shall close it. logFilePtr.i = logFilePtr.p->prevLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); exitFromInvalidate(signal); return; break; case LogFileRecord::CLOSING_INIT: jam(); closingInitLab(signal); return; break; case LogFileRecord::CLOSING_SR: jam(); closingSrLab(signal); return; break; case LogFileRecord::CLOSING_EXEC_SR: jam(); closeExecSrLab(signal); return; break; case LogFileRecord::CLOSING_EXEC_SR_COMPLETED: jam(); closeExecSrCompletedLab(signal); return; break; case LogFileRecord::CLOSING_WRITE_LOG: jam(); closeWriteLogLab(signal); return; break; case LogFileRecord::CLOSING_EXEC_LOG: jam(); closeExecLogLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch }//Dblqh::execFSCLOSECONF() /* ************>> */ /* FSCLOSEREF > */ /* ************>> */ void Dblqh::execFSCLOSEREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; systemErrorLab(signal); return; }//Dblqh::execFSCLOSEREF() /* ************>> */ /* FSOPENCONF > */ /* ************>> */ void Dblqh::execFSOPENCONF(Signal* signal) { jamEntry(); initFsopenconf(signal); switch (logFilePtr.p->logFileStatus) { case LogFileRecord::OPEN_SR_INVALIDATE_PAGES: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; readFileInInvalidate(signal); return; break; case LogFileRecord::OPENING_INIT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openFileInitLab(signal); return; break; case LogFileRecord::OPEN_SR_FRONTPAGE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFrontpageLab(signal); return; break; case LogFileRecord::OPEN_SR_LAST_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrLastFileLab(signal); return; break; case LogFileRecord::OPEN_SR_NEXT_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrNextFileLab(signal); return; break; case LogFileRecord::OPEN_EXEC_SR_START: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrStartLab(signal); return; break; case LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrNewMbyteLab(signal); return; break; case LogFileRecord::OPEN_SR_FOURTH_PHASE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthPhaseLab(signal); return; break; case LogFileRecord::OPEN_SR_FOURTH_NEXT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthNextLab(signal); return; break; case LogFileRecord::OPEN_SR_FOURTH_ZERO: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthZeroLab(signal); return; break; case LogFileRecord::OPENING_WRITE_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; return; break; case LogFileRecord::OPEN_EXEC_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecLogLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch }//Dblqh::execFSOPENCONF() /* ************> */ /* FSOPENREF > */ /* ************> */ void Dblqh::execFSOPENREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; systemErrorLab(signal); return; }//Dblqh::execFSOPENREF() /* ************>> */ /* FSREADCONF > */ /* ************>> */ void Dblqh::execFSREADCONF(Signal* signal) { jamEntry(); initFsrwconf(signal); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::READ_SR_LAST_MBYTE: jam(); releaseLfo(signal); readSrLastMbyteLab(signal); return; break; case LogFileOperationRecord::READ_SR_FRONTPAGE: jam(); releaseLfo(signal); readSrFrontpageLab(signal); return; break; case LogFileOperationRecord::READ_SR_LAST_FILE: jam(); releaseLfo(signal); readSrLastFileLab(signal); return; break; case LogFileOperationRecord::READ_SR_NEXT_FILE: jam(); releaseLfo(signal); readSrNextFileLab(signal); return; break; case LogFileOperationRecord::READ_EXEC_SR: jam(); readExecSrLab(signal); return; break; case LogFileOperationRecord::READ_EXEC_LOG: jam(); readExecLogLab(signal); return; break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; break; case LogFileOperationRecord::READ_SR_FOURTH_PHASE: jam(); releaseLfo(signal); readSrFourthPhaseLab(signal); return; break; case LogFileOperationRecord::READ_SR_FOURTH_ZERO: jam(); releaseLfo(signal); readSrFourthZeroLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch }//Dblqh::execFSREADCONF() /* ************>> */ /* FSREADCONF > */ /* ************>> */ void Dblqh::execFSREADREF(Signal* signal) { jamEntry(); lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); terrorCode = signal->theData[1]; switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::READ_SR_LAST_MBYTE: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_FRONTPAGE: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_LAST_FILE: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_NEXT_FILE: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_EXEC_SR: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_EXEC_LOG: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_FOURTH_PHASE: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_FOURTH_ZERO: jam(); systemErrorLab(signal); return; break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam() systemErrorLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch return; }//Dblqh::execFSREADREF() /* *************** */ /* FSWRITECONF > */ /* *************** */ void Dblqh::execFSWRITECONF(Signal* signal) { jamEntry(); initFsrwconf(signal); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; break; case LogFileOperationRecord::WRITE_PAGE_ZERO: jam(); writePageZeroLab(signal); return; break; case LogFileOperationRecord::LAST_WRITE_IN_FILE: jam(); lastWriteInFileLab(signal); return; break; case LogFileOperationRecord::INIT_WRITE_AT_END: jam(); initWriteEndLab(signal); return; break; case LogFileOperationRecord::INIT_FIRST_PAGE: jam(); initFirstPageLab(signal); return; break; case LogFileOperationRecord::WRITE_GCI_ZERO: jam(); writeGciZeroLab(signal); return; break; case LogFileOperationRecord::WRITE_DIRTY: jam(); writeDirtyLab(signal); return; break; case LogFileOperationRecord::WRITE_INIT_MBYTE: jam(); writeInitMbyteLab(signal); return; break; case LogFileOperationRecord::ACTIVE_WRITE_LOG: jam(); writeLogfileLab(signal); return; break; case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: jam(); firstPageWriteLab(signal); return; break; default: jam(); systemErrorLab(signal); return; break; }//switch }//Dblqh::execFSWRITECONF() /* ************>> */ /* FSWRITEREF > */ /* ************>> */ void Dblqh::execFSWRITEREF(Signal* signal) { jamEntry(); lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); terrorCode = signal->theData[1]; switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_PAGE_ZERO: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::LAST_WRITE_IN_FILE: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::INIT_WRITE_AT_END: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::INIT_FIRST_PAGE: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_GCI_ZERO: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_DIRTY: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_INIT_MBYTE: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::ACTIVE_WRITE_LOG: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: jam(); systemErrorLab(signal); break; case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); systemErrorLab(signal); break; default: jam(); systemErrorLab(signal); break; }//switch }//Dblqh::execFSWRITEREF() /* ========================================================================= */ /* ======= INITIATE WHEN RECEIVING FSOPENCONF ======= */ /* */ /* ========================================================================= */ void Dblqh::initFsopenconf(Signal* signal) { logFilePtr.i = signal->theData[0]; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logFilePtr.p->fileRef = signal->theData[1]; logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.p->currentMbyte = 0; logFilePtr.p->filePosition = 0; logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; }//Dblqh::initFsopenconf() /* ========================================================================= */ /* ======= INITIATE WHEN RECEIVING FSREADCONF AND FSWRITECONF ======= */ /* */ /* ========================================================================= */ void Dblqh::initFsrwconf(Signal* signal) { lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); logFilePtr.i = lfoPtr.p->logFileRec; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logPagePtr.i = lfoPtr.p->firstLfoPage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); }//Dblqh::initFsrwconf() /* ######################################################################### */ /* NORMAL OPERATION MODULE */ /* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ /* */ /* THIS PART HANDLES THE NORMAL OPENING, CLOSING AND WRITING OF LOG FILES */ /* DURING NORMAL OPERATION. */ /* ######################################################################### */ /*---------------------------------------------------------------------------*/ /* THIS SIGNAL IS USED TO SUPERVISE THAT THE LOG RECORDS ARE NOT KEPT IN MAIN*/ /* MEMORY FOR MORE THAN 1 SECOND TO ACHIEVE THE PROPER RELIABILITY. */ /*---------------------------------------------------------------------------*/ void Dblqh::timeSup(Signal* signal) { LogPageRecordPtr origLogPagePtr; Uint32 wordWritten; jamEntry(); logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); if (logPartPtr.p->logPartTimer != logPartPtr.p->logTimer) { jam(); /*--------------------------------------------------------------------------*/ /* THIS LOG PART HAS NOT WRITTEN TO DISK DURING THE LAST SECOND. */ /*--------------------------------------------------------------------------*/ switch (logPartPtr.p->logPartState) { case LogPartRecord::FILE_CHANGE_PROBLEM: jam(); /*--------------------------------------------------------------------------*/ /* THIS LOG PART HAS PROBLEMS IN CHANGING FILES MAKING IT IMPOSSIBLE */ // TO WRITE TO THE FILE CURRENTLY. WE WILL COMEBACK LATER AND SEE IF // THE PROBLEM HAS BEEN FIXED. /*--------------------------------------------------------------------------*/ case LogPartRecord::ACTIVE: jam(); /*---------------------------------------------------------------------------*/ /* AN OPERATION IS CURRENTLY ACTIVE IN WRITING THIS LOG PART. WE THUS CANNOT */ /* WRITE ANYTHING TO DISK AT THIS MOMENT. WE WILL SEND A SIGNAL DELAYED FOR */ /* 10 MS AND THEN TRY AGAIN. POSSIBLY THE LOG PART WILL HAVE BEEN WRITTEN */ /* UNTIL THEN OR ELSE IT SHOULD BE FREE TO WRITE AGAIN. */ /*---------------------------------------------------------------------------*/ signal->theData[0] = ZTIME_SUPERVISION; signal->theData[1] = logPartPtr.i; sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); return; break; case LogPartRecord::IDLE: case LogPartRecord::TAIL_PROBLEM: jam(); /*---------------------------------------------------------------------------*/ /* IDLE AND NOT WRITTEN TO DISK IN A SECOND. ALSO WHEN WE HAVE A TAIL PROBLEM*/ /* WE HAVE TO WRITE TO DISK AT TIMES. WE WILL FIRST CHECK WHETHER ANYTHING */ /* AT ALL HAVE BEEN WRITTEN TO THE PAGES BEFORE WRITING TO DISK. */ /*---------------------------------------------------------------------------*/ /* WE HAVE TO WRITE TO DISK IN ALL CASES SINCE THERE COULD BE INFORMATION */ /* STILL IN THE LOG THAT WAS GENERATED BEFORE THE PREVIOUS TIME SUPERVISION */ /* BUT AFTER THE LAST DISK WRITE. THIS PREVIOUSLY STOPPED ALL DISK WRITES */ /* WHEN NO MORE LOG WRITES WERE PERFORMED (THIS HAPPENED WHEN LOG GOT FULL */ /* AND AFTER LOADING THE INITIAL RECORDS IN INITIAL START). */ /*---------------------------------------------------------------------------*/ if (((logFilePtr.p->currentFilepage + 1) & (ZPAGES_IN_MBYTE -1)) == 0) { jam(); /*---------------------------------------------------------------------------*/ /* THIS IS THE LAST PAGE IN THIS MBYTE. WRITE NEXT LOG AND SWITCH TO NEXT */ /* MBYTE. */ /*---------------------------------------------------------------------------*/ changeMbyte(signal); } else { /*---------------------------------------------------------------------------*/ /* WRITE THE LOG PAGE TO DISK EVEN IF IT IS NOT FULL. KEEP PAGE AND WRITE A */ /* COPY. THE ORIGINAL PAGE WILL BE WRITTEN AGAIN LATER ON. */ /*---------------------------------------------------------------------------*/ wordWritten = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1; origLogPagePtr.i = logPagePtr.i; origLogPagePtr.p = logPagePtr.p; seizeLogpage(signal); MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[0], &origLogPagePtr.p->logPageWord[0], wordWritten + 1); ndbrequire(wordWritten < ZPAGE_SIZE); if (logFilePtr.p->noLogpagesInBuffer > 0) { jam(); completedLogPage(signal, ZENFORCE_WRITE); /*---------------------------------------------------------------------------*/ /*SINCE WE ARE ONLY WRITING PART OF THE LAST PAGE WE HAVE TO UPDATE THE WORD */ /*WRITTEN TO REFLECT THE REAL LAST WORD WRITTEN. WE ALSO HAVE TO MOVE THE */ /*FILE POSITION ONE STEP BACKWARDS SINCE WE ARE NOT WRITING THE LAST PAGE */ /*COMPLETELY. IT WILL BE WRITTEN AGAIN. */ /*---------------------------------------------------------------------------*/ lfoPtr.p->lfoWordWritten = wordWritten; logFilePtr.p->filePosition = logFilePtr.p->filePosition - 1; } else { if (wordWritten == (ZPAGE_HEADER_SIZE - 1)) { /*---------------------------------------------------------------------------*/ /*THIS IS POSSIBLE BUT VERY UNLIKELY. IF THE PAGE WAS COMPLETED AFTER THE LAST*/ /*WRITE TO DISK THEN NO_LOG_PAGES_IN_BUFFER > 0 AND IF NOT WRITTEN SINCE LAST*/ /*WRITE TO DISK THEN THE PREVIOUS PAGE MUST HAVE BEEN WRITTEN BY SOME */ /*OPERATION AND THAT BECAME COMPLETELY FULL. IN ANY CASE WE NEED NOT WRITE AN*/ /*EMPTY PAGE TO DISK. */ /*---------------------------------------------------------------------------*/ jam(); releaseLogpage(signal); } else { jam(); writeSinglePage(signal, logFilePtr.p->currentFilepage, wordWritten); lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; }//if }//if }//if break; default: ndbrequire(false); break; }//switch }//if logPartPtr.p->logTimer++; return; }//Dblqh::timeSup() void Dblqh::writeLogfileLab(Signal* signal) { /*---------------------------------------------------------------------------*/ /* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK */ /* WRITE. */ /*---------------------------------------------------------------------------*/ switch (logFilePtr.p->fileChangeState) { case LogFileRecord::NOT_ONGOING: jam(); checkGcpCompleted(signal, ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1), lfoPtr.p->lfoWordWritten); break; #if 0 case LogFileRecord::BOTH_WRITES_ONGOING: jam(); ndbout_c("not crashing!!"); // Fall-through #endif case LogFileRecord::WRITE_PAGE_ZERO_ONGOING: case LogFileRecord::LAST_WRITE_ONGOING: jam(); logFilePtr.p->lastPageWritten = (lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1; logFilePtr.p->lastWordWritten = lfoPtr.p->lfoWordWritten; break; default: jam(); systemErrorLab(signal); return; break; }//switch releaseLfoPages(signal); releaseLfo(signal); return; }//Dblqh::writeLogfileLab() void Dblqh::closeWriteLogLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; return; }//Dblqh::closeWriteLogLab() /* ######################################################################### */ /* FILE CHANGE MODULE */ /* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ /* */ /*THIS PART OF THE FILE MODULE HANDLES WHEN WE ARE CHANGING LOG FILE DURING */ /*NORMAL OPERATION. WE HAVE TO BE CAREFUL WHEN WE ARE CHANGING LOG FILE SO */ /*THAT WE DO NOT COMPLICATE THE SYSTEM RESTART PROCESS TOO MUCH. */ /*THE IDEA IS THAT WE START BY WRITING THE LAST WRITE IN THE OLD FILE AND WE */ /*ALSO WRITE THE FIRST PAGE OF THE NEW FILE CONCURRENT WITH THAT. THIS FIRST */ /*PAGE IN THE NEW FILE DO NOT CONTAIN ANY LOG RECORDS OTHER THAN A DESCRIPTOR*/ /*CONTAINING INFORMATION ABOUT GCI'S NEEDED AT SYSTEM RESTART AND A NEXT LOG */ /*RECORD. */ /* */ /*WHEN BOTH OF THOSE WRITES HAVE COMPLETED WE ALSO WRITE PAGE ZERO IN FILE */ /*ZERO. THE ONLY INFORMATION WHICH IS INTERESTING HERE IS THE NEW FILE NUMBER*/ /* */ /*IF OPTIMISATIONS ARE NEEDED OF THE LOG HANDLING THEN IT IS POSSIBLE TO */ /*AVOID WRITING THE FIRST PAGE OF THE NEW PAGE IMMEDIATELY. THIS COMPLICATES */ /*THE SYSTEM RESTART AND ONE HAS TO TAKE SPECIAL CARE WITH FILE ZERO. IT IS */ /*HOWEVER NO LARGE PROBLEM TO CHANGE INTO THIS SCENARIO. TO AVOID ALSO THE */ /*WRITING OF PAGE ZERO IS ALSO POSSIBLE BUT COMPLICATES THE DESIGN EVEN */ /*FURTHER. IT GETS FAIRLY COMPLEX TO FIND THE END OF THE LOG. SOME SORT OF */ /*BINARY SEARCH IS HOWEVER MOST LIKELY A GOOD METHODOLOGY FOR THIS. */ /* ######################################################################### */ void Dblqh::firstPageWriteLab(Signal* signal) { releaseLfo(signal); /*---------------------------------------------------------------------------*/ /* RELEASE PAGE ZERO IF THE FILE IS NOT FILE 0. */ /*---------------------------------------------------------------------------*/ Uint32 fileNo = logFilePtr.p->fileNo; if (fileNo != 0) { jam(); releaseLogpage(signal); }//if /*---------------------------------------------------------------------------*/ /* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN */ /* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE */ /* LAST FILE WHERE LOGGING HAS STARTED. */ /*---------------------------------------------------------------------------*/ /* FIRST CHECK WHETHER THE LAST WRITE IN THE PREVIOUS FILE HAVE COMPLETED */ /*---------------------------------------------------------------------------*/ if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) { jam(); /*---------------------------------------------------------------------------*/ /* THE LAST WRITE WAS STILL ONGOING. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::LAST_WRITE_ONGOING; return; } else { jam(); ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::FIRST_WRITE_ONGOING); /*---------------------------------------------------------------------------*/ /* WRITE TO PAGE 0 IN IN FILE 0 NOW. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING; if (fileNo == 0) { jam(); /*---------------------------------------------------------------------------*/ /* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; return; } else { jam(); /*---------------------------------------------------------------------------*/ /* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE */ /* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS */ /* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE. */ /* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE */ /* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE */ /* LOG PART. */ /*---------------------------------------------------------------------------*/ Uint32 currLogFile = logFilePtr.i; logFilePtr.i = logPartPtr.p->firstLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; writeSinglePage(signal, 0, ZPAGE_SIZE - 1); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; }//if }//if }//Dblqh::firstPageWriteLab() void Dblqh::lastWriteInFileLab(Signal* signal) { LogFileRecordPtr locLogFilePtr; /*---------------------------------------------------------------------------*/ /* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK */ /* WRITE. */ /*---------------------------------------------------------------------------*/ checkGcpCompleted(signal, ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1), (ZPAGE_SIZE - 1)); releaseLfoPages(signal); releaseLfo(signal); /*---------------------------------------------------------------------------*/ /* IF THE FILE IS NOT IN USE OR THE NEXT FILE TO BE USED WE WILL CLOSE IT. */ /*---------------------------------------------------------------------------*/ locLogFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); if (logFilePtr.i != locLogFilePtr.i) { if (logFilePtr.i != locLogFilePtr.p->nextLogFile) { if (logFilePtr.p->fileNo != 0) { jam(); /*---------------------------------------------------------------------------*/ /* THE FILE IS NOT FILE ZERO EITHER. WE WILL NOT CLOSE FILE ZERO SINCE WE */ /* USE IT TO KEEP TRACK OF THE CURRENT LOG FILE BY WRITING PAGE ZERO IN */ /* FILE ZERO. */ /*---------------------------------------------------------------------------*/ /* WE WILL CLOSE THE FILE. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_WRITE_LOG; closeFile(signal, logFilePtr); }//if }//if }//if /*---------------------------------------------------------------------------*/ /* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN */ /* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE */ /* LAST FILE WHERE LOGGING HAS STARTED. */ /*---------------------------------------------------------------------------*/ /* FIRST CHECK WHETHER THE FIRST WRITE IN THE NEW FILE HAVE COMPLETED */ /* THIS STATE INFORMATION IS IN THE NEW LOG FILE AND THUS WE HAVE TO MOVE */ /* THE LOG FILE POINTER TO THIS LOG FILE. */ /*---------------------------------------------------------------------------*/ logFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) { jam(); /*---------------------------------------------------------------------------*/ /* THE FIRST WRITE WAS STILL ONGOING. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::FIRST_WRITE_ONGOING; return; } else { ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::LAST_WRITE_ONGOING); /*---------------------------------------------------------------------------*/ /* WRITE TO PAGE 0 IN IN FILE 0 NOW. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING; Uint32 fileNo = logFilePtr.p->fileNo; if (fileNo == 0) { jam(); /*---------------------------------------------------------------------------*/ /* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; return; } else { jam(); /*---------------------------------------------------------------------------*/ /* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE */ /* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS */ /* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE. */ /* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE */ /* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE */ /* LOG PART. */ /*---------------------------------------------------------------------------*/ Uint32 currLogFile = logFilePtr.i; logFilePtr.i = logPartPtr.p->firstLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; writeSinglePage(signal, 0, ZPAGE_SIZE - 1); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; }//if }//if }//Dblqh::lastWriteInFileLab() void Dblqh::writePageZeroLab(Signal* signal) { logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; /*---------------------------------------------------------------------------*/ /* IT COULD HAVE ARRIVED PAGE WRITES TO THE CURRENT FILE WHILE WE WERE */ /* WAITING FOR THIS DISK WRITE TO COMPLETE. THEY COULD NOT CHECK FOR */ /* COMPLETED GLOBAL CHECKPOINTS. THUS WE SHOULD DO THAT NOW INSTEAD. */ /*---------------------------------------------------------------------------*/ checkGcpCompleted(signal, logFilePtr.p->lastPageWritten, logFilePtr.p->lastWordWritten); releaseLfo(signal); return; }//Dblqh::writePageZeroLab() /* ######################################################################### */ /* INITIAL START MODULE */ /* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ /* */ /*THIS MODULE INITIALISES ALL THE LOG FILES THAT ARE NEEDED AT A SYSTEM */ /*RESTART AND WHICH ARE USED DURING NORMAL OPERATIONS. IT CREATES THE FILES */ /*AND SETS A PROPER SIZE OF THEM AND INITIALISES THE FIRST PAGE IN EACH FILE */ /* ######################################################################### */ void Dblqh::openFileInitLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::OPEN_INIT; seizeLogpage(signal); writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, ZPAGE_SIZE - 1); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_WRITE_AT_END; return; }//Dblqh::openFileInitLab() void Dblqh::initWriteEndLab(Signal* signal) { releaseLfo(signal); initLogpage(signal); if (logFilePtr.p->fileNo == 0) { jam(); /*---------------------------------------------------------------------------*/ /* PAGE ZERO IN FILE ZERO MUST SET LOG LAP TO ONE SINCE IT HAS STARTED */ /* WRITING TO THE LOG, ALSO GLOBAL CHECKPOINTS ARE SET TO ZERO. */ /*---------------------------------------------------------------------------*/ logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = 0; logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] = 0; logFilePtr.p->logMaxGciStarted[0] = 0; logFilePtr.p->logMaxGciCompleted[0] = 0; }//if /*---------------------------------------------------------------------------*/ /* REUSE CODE FOR INITIALISATION OF FIRST PAGE IN ALL LOG FILES. */ /*---------------------------------------------------------------------------*/ writeFileHeaderOpen(signal, ZINIT); return; }//Dblqh::initWriteEndLab() void Dblqh::initFirstPageLab(Signal* signal) { releaseLfo(signal); if (logFilePtr.p->fileNo == 0) { jam(); /*---------------------------------------------------------------------------*/ /* IN FILE ZERO WE WILL INSERT A PAGE ONE WHERE WE WILL INSERT A COMPLETED */ /* GCI RECORD FOR GCI = 0. */ /*---------------------------------------------------------------------------*/ initLogpage(signal); logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE] = ZCOMPLETED_GCI_TYPE; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + 1] = 1; writeSinglePage(signal, 1, ZPAGE_SIZE - 1); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_GCI_ZERO; return; }//if logFilePtr.p->currentMbyte = 1; writeInitMbyte(signal); return; }//Dblqh::initFirstPageLab() void Dblqh::writeGciZeroLab(Signal* signal) { releaseLfo(signal); logFilePtr.p->currentMbyte = 1; writeInitMbyte(signal); return; }//Dblqh::writeGciZeroLab() void Dblqh::writeInitMbyteLab(Signal* signal) { releaseLfo(signal); logFilePtr.p->currentMbyte = logFilePtr.p->currentMbyte + 1; if (logFilePtr.p->currentMbyte == ZNO_MBYTES_IN_FILE) { jam(); releaseLogpage(signal); logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_INIT; closeFile(signal, logFilePtr); return; }//if writeInitMbyte(signal); return; }//Dblqh::writeInitMbyteLab() void Dblqh::closingInitLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); if (logFilePtr.p->nextLogFile == logPartPtr.p->firstLogfile) { jam(); checkInitCompletedLab(signal); return; } else { jam(); logFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); openLogfileInit(signal); }//if return; }//Dblqh::closingInitLab() void Dblqh::checkInitCompletedLab(Signal* signal) { logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED; /*---------------------------------------------------------------------------*/ /* WE HAVE NOW INITIALISED ALL FILES IN THIS LOG PART. WE CAN NOW SET THE */ /* THE LOG LAP TO ONE SINCE WE WILL START WITH LOG LAP ONE. LOG LAP = ZERO */ /* MEANS THIS PART OF THE LOG IS NOT WRITTEN YET. */ /*---------------------------------------------------------------------------*/ logPartPtr.p->logLap = 1; logPartPtr.i = 0; CHECK_LOG_PARTS_LOOP: ptrAss(logPartPtr, logPartRecord); if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED) { jam(); /*---------------------------------------------------------------------------*/ /* THIS PART HAS STILL NOT COMPLETED. WAIT FOR THIS TO OCCUR. */ /*---------------------------------------------------------------------------*/ return; }//if if (logPartPtr.i == 3) { jam(); /*---------------------------------------------------------------------------*/ /* ALL LOG PARTS ARE COMPLETED. NOW WE CAN CONTINUE WITH THE RESTART */ /* PROCESSING. THE NEXT STEP IS TO PREPARE FOR EXECUTING OPERATIONS. THUS WE */ /* NEED TO INITIALISE ALL NEEDED DATA AND TO OPEN FILE ZERO AND THE NEXT AND */ /* TO SET THE CURRENT LOG PAGE TO BE PAGE 1 IN FILE ZERO. */ /*---------------------------------------------------------------------------*/ for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { ptrAss(logPartPtr, logPartRecord); signal->theData[0] = ZINIT_FOURTH; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//for return; } else { jam(); logPartPtr.i = logPartPtr.i + 1; goto CHECK_LOG_PARTS_LOOP; }//if }//Dblqh::checkInitCompletedLab() /* ========================================================================= */ /* ======= INITIATE LOG FILE OPERATION RECORD WHEN ALLOCATED ======= */ /* */ /* ========================================================================= */ void Dblqh::initLfo(Signal* signal) { lfoPtr.p->firstLfoPage = RNIL; lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; lfoPtr.p->logFileRec = logFilePtr.i; lfoPtr.p->noPagesRw = 0; lfoPtr.p->lfoPageNo = ZNIL; }//Dblqh::initLfo() /* ========================================================================= */ /* ======= INITIATE LOG FILE WHEN ALLOCATED ======= */ /* */ /* INPUT: TFILE_NO NUMBER OF THE FILE INITIATED */ /* LOG_PART_PTR NUMBER OF LOG PART */ /* SUBROUTINE SHORT NAME = IL */ /* ========================================================================= */ void Dblqh::initLogfile(Signal* signal, Uint32 fileNo) { UintR tilTmp; UintR tilIndex; logFilePtr.p->currentFilepage = 0; logFilePtr.p->currentLogpage = RNIL; logFilePtr.p->fileName[0] = (UintR)-1; logFilePtr.p->fileName[1] = (UintR)-1; /* = H'FFFFFFFF = -1 */ logFilePtr.p->fileName[2] = fileNo; /* Sfile_no */ tilTmp = 1; /* VERSION 1 OF FILE NAME */ tilTmp = (tilTmp << 8) + 1; /* FRAGMENT LOG => .FRAGLOG AS EXTENSION */ tilTmp = (tilTmp << 8) + (8 + logPartPtr.i); /* DIRECTORY = D(8+Part)/DBLQH */ tilTmp = (tilTmp << 8) + 255; /* IGNORE Pxx PART OF FILE NAME */ logFilePtr.p->fileName[3] = tilTmp; /* ========================================================================= */ /* FILE NAME BECOMES /D2/DBLQH/Tpart_no/Sfile_no.FRAGLOG */ /* ========================================================================= */ logFilePtr.p->fileNo = fileNo; logFilePtr.p->filePosition = 0; logFilePtr.p->firstLfo = RNIL; logFilePtr.p->lastLfo = RNIL; logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; logFilePtr.p->logPartRec = logPartPtr.i; logFilePtr.p->noLogpagesInBuffer = 0; logFilePtr.p->firstFilledPage = RNIL; logFilePtr.p->lastFilledPage = RNIL; logFilePtr.p->lastPageWritten = 0; logFilePtr.p->logPageZero = RNIL; logFilePtr.p->currentMbyte = 0; for (tilIndex = 0; tilIndex <= 15; tilIndex++) { logFilePtr.p->logMaxGciCompleted[tilIndex] = (UintR)-1; logFilePtr.p->logMaxGciStarted[tilIndex] = (UintR)-1; logFilePtr.p->logLastPrepRef[tilIndex] = 0; }//for }//Dblqh::initLogfile() /* ========================================================================= */ /* ======= INITIATE LOG PAGE WHEN ALLOCATED ======= */ /* */ /* ========================================================================= */ void Dblqh::initLogpage(Signal* signal) { TcConnectionrecPtr ilpTcConnectptr; logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = logPartPtr.p->logLap; logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] = logPartPtr.p->logPartNewestCompletedGCI; logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = cnewestGci; logPagePtr.p->logPageWord[ZPOS_VERSION] = NDB_VERSION; logPagePtr.p->logPageWord[ZPOS_NO_LOG_FILES] = logPartPtr.p->noLogFiles; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; ilpTcConnectptr.i = logPartPtr.p->firstLogTcrec; if (ilpTcConnectptr.i != RNIL) { jam(); ptrCheckGuard(ilpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] = (ilpTcConnectptr.p->logStartFileNo << 16) + (ilpTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE); } else { jam(); logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] = (logFilePtr.p->fileNo << 16) + (logFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE); }//if }//Dblqh::initLogpage() /* ------------------------------------------------------------------------- */ /* ------- OPEN LOG FILE FOR READ AND WRITE ------- */ /* */ /* SUBROUTINE SHORT NAME = OFR */ /* ------------------------------------------------------------------------- */ void Dblqh::openFileRw(Signal* signal, LogFileRecordPtr olfLogFilePtr) { signal->theData[0] = cownref; signal->theData[1] = olfLogFilePtr.i; signal->theData[2] = olfLogFilePtr.p->fileName[0]; signal->theData[3] = olfLogFilePtr.p->fileName[1]; signal->theData[4] = olfLogFilePtr.p->fileName[2]; signal->theData[5] = olfLogFilePtr.p->fileName[3]; signal->theData[6] = ZOPEN_READ_WRITE; sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); }//Dblqh::openFileRw() /* ------------------------------------------------------------------------- */ /* ------- OPEN LOG FILE DURING INITIAL START ------- */ /* */ /* SUBROUTINE SHORT NAME = OLI */ /* ------------------------------------------------------------------------- */ void Dblqh::openLogfileInit(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::OPENING_INIT; signal->theData[0] = cownref; signal->theData[1] = logFilePtr.i; signal->theData[2] = logFilePtr.p->fileName[0]; signal->theData[3] = logFilePtr.p->fileName[1]; signal->theData[4] = logFilePtr.p->fileName[2]; signal->theData[5] = logFilePtr.p->fileName[3]; signal->theData[6] = 0x302; sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); }//Dblqh::openLogfileInit() /* OPEN FOR READ/WRITE, DO CREATE AND DO TRUNCATE FILE */ /* ------------------------------------------------------------------------- */ /* ------- OPEN NEXT LOG FILE ------- */ /* */ /* SUBROUTINE SHORT NAME = ONL */ /* ------------------------------------------------------------------------- */ void Dblqh::openNextLogfile(Signal* signal) { LogFileRecordPtr onlLogFilePtr; if (logPartPtr.p->noLogFiles > 2) { jam(); /* -------------------------------------------------- */ /* IF ONLY 1 OR 2 LOG FILES EXIST THEN THEY ARE */ /* ALWAYS OPEN AND THUS IT IS NOT NECESSARY TO */ /* OPEN THEM NOW. */ /* -------------------------------------------------- */ onlLogFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(onlLogFilePtr, clogFileFileSize, logFileRecord); if (onlLogFilePtr.p->logFileStatus != LogFileRecord::CLOSED) { ndbrequire(onlLogFilePtr.p->fileNo == 0); return; }//if onlLogFilePtr.p->logFileStatus = LogFileRecord::OPENING_WRITE_LOG; signal->theData[0] = cownref; signal->theData[1] = onlLogFilePtr.i; signal->theData[2] = onlLogFilePtr.p->fileName[0]; signal->theData[3] = onlLogFilePtr.p->fileName[1]; signal->theData[4] = onlLogFilePtr.p->fileName[2]; signal->theData[5] = onlLogFilePtr.p->fileName[3]; signal->theData[6] = 2; sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); }//if }//Dblqh::openNextLogfile() /* OPEN FOR READ/WRITE, DON'T CREATE AND DON'T TRUNCATE FILE */ /* ------------------------------------------------------------------------- */ /* ------- RELEASE LFO RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::releaseLfo(Signal* signal) { #ifdef VM_TRACE // Check that lfo record isn't already in free list LogFileOperationRecordPtr TlfoPtr; TlfoPtr.i = cfirstfreeLfo; while (TlfoPtr.i != RNIL){ ptrCheckGuard(TlfoPtr, clfoFileSize, logFileOperationRecord); ndbrequire(TlfoPtr.i != lfoPtr.i); TlfoPtr.i = TlfoPtr.p->nextLfo; } #endif lfoPtr.p->nextLfo = cfirstfreeLfo; lfoPtr.p->lfoTimer = 0; cfirstfreeLfo = lfoPtr.i; lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; }//Dblqh::releaseLfo() /* ------------------------------------------------------------------------- */ /* ------- RELEASE ALL LOG PAGES CONNECTED TO A LFO RECORD ------- */ /* */ /* SUBROUTINE SHORT NAME = RLP */ /* ------------------------------------------------------------------------- */ void Dblqh::releaseLfoPages(Signal* signal) { LogPageRecordPtr rlpLogPagePtr; logPagePtr.i = lfoPtr.p->firstLfoPage; RLP_LOOP: ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); rlpLogPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; releaseLogpage(signal); if (rlpLogPagePtr.i != RNIL) { jam(); logPagePtr.i = rlpLogPagePtr.i; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); goto RLP_LOOP; }//if lfoPtr.p->firstLfoPage = RNIL; }//Dblqh::releaseLfoPages() /* ------------------------------------------------------------------------- */ /* ------- RELEASE LOG PAGE ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::releaseLogpage(Signal* signal) { #ifdef VM_TRACE // Check that log page isn't already in free list LogPageRecordPtr TlogPagePtr; TlogPagePtr.i = cfirstfreeLogPage; while (TlogPagePtr.i != RNIL){ ptrCheckGuard(TlogPagePtr, clogPageFileSize, logPageRecord); ndbrequire(TlogPagePtr.i != logPagePtr.i); TlogPagePtr.i = TlogPagePtr.p->logPageWord[ZNEXT_PAGE]; } #endif cnoOfLogPages++; logPagePtr.p->logPageWord[ZNEXT_PAGE] = cfirstfreeLogPage; cfirstfreeLogPage = logPagePtr.i; }//Dblqh::releaseLogpage() /* ------------------------------------------------------------------------- */ /* ------- SEIZE LFO RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::seizeLfo(Signal* signal) { lfoPtr.i = cfirstfreeLfo; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); cfirstfreeLfo = lfoPtr.p->nextLfo; lfoPtr.p->nextLfo = RNIL; lfoPtr.p->lfoTimer = cLqhTimeOutCount; }//Dblqh::seizeLfo() /* ------------------------------------------------------------------------- */ /* ------- SEIZE LOG FILE RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::seizeLogfile(Signal* signal) { logFilePtr.i = cfirstfreeLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); /* ------------------------------------------------------------------------- */ /*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_FILE_PTR = RNIL */ /* ------------------------------------------------------------------------- */ cfirstfreeLogFile = logFilePtr.p->nextLogFile; logFilePtr.p->nextLogFile = RNIL; }//Dblqh::seizeLogfile() /* ------------------------------------------------------------------------- */ /* ------- SEIZE LOG PAGE RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::seizeLogpage(Signal* signal) { cnoOfLogPages--; logPagePtr.i = cfirstfreeLogPage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); /* ------------------------------------------------------------------------- */ /*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_PAGE_PTR = RNIL */ /* ------------------------------------------------------------------------- */ cfirstfreeLogPage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; }//Dblqh::seizeLogpage() /* ------------------------------------------------------------------------- */ /* ------- WRITE FILE DESCRIPTOR INFORMATION ------- */ /* */ /* SUBROUTINE SHORT NAME: WFD */ // Pointer handling: // logFilePtr in // logPartPtr in /* ------------------------------------------------------------------------- */ void Dblqh::writeFileDescriptor(Signal* signal) { TcConnectionrecPtr wfdTcConnectptr; UintR twfdFileNo; UintR twfdMbyte; /* -------------------------------------------------- */ /* START BY WRITING TO LOG FILE RECORD */ /* -------------------------------------------------- */ arrGuard(logFilePtr.p->currentMbyte, 16); logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] = logPartPtr.p->logPartNewestCompletedGCI; logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] = cnewestGci; wfdTcConnectptr.i = logPartPtr.p->firstLogTcrec; if (wfdTcConnectptr.i != RNIL) { jam(); ptrCheckGuard(wfdTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); twfdFileNo = wfdTcConnectptr.p->logStartFileNo; twfdMbyte = wfdTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE; logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = (twfdFileNo << 16) + twfdMbyte; } else { jam(); logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = (logFilePtr.p->fileNo << 16) + logFilePtr.p->currentMbyte; }//if }//Dblqh::writeFileDescriptor() /* ------------------------------------------------------------------------- */ /* ------- WRITE THE HEADER PAGE OF A NEW FILE ------- */ /* */ /* SUBROUTINE SHORT NAME: WMO */ /* ------------------------------------------------------------------------- */ void Dblqh::writeFileHeaderOpen(Signal* signal, Uint32 wmoType) { LogFileRecordPtr wmoLogFilePtr; UintR twmoNoLogDescriptors; UintR twmoLoop; UintR twmoIndex; /* -------------------------------------------------- */ /* WRITE HEADER INFORMATION IN THE NEW FILE. */ /* -------------------------------------------------- */ logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_LOG_TYPE] = ZFD_TYPE; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = logFilePtr.p->fileNo; if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { jam(); twmoNoLogDescriptors = ZMAX_LOG_FILES_IN_PAGE_ZERO; } else { jam(); twmoNoLogDescriptors = logPartPtr.p->noLogFiles; }//if logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD] = twmoNoLogDescriptors; wmoLogFilePtr.i = logFilePtr.i; twmoLoop = 0; WMO_LOOP: jam(); if (twmoLoop < twmoNoLogDescriptors) { jam(); ptrCheckGuard(wmoLogFilePtr, clogFileFileSize, logFileRecord); for (twmoIndex = 0; twmoIndex <= ZNO_MBYTES_IN_FILE - 1; twmoIndex++) { jam(); arrGuard(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + twmoIndex, ZPAGE_SIZE); logPagePtr.p->logPageWord[((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + twmoIndex] = wmoLogFilePtr.p->logMaxGciCompleted[twmoIndex]; arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + ZNO_MBYTES_IN_FILE) + twmoIndex, ZPAGE_SIZE); logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + ZNO_MBYTES_IN_FILE) + twmoIndex] = wmoLogFilePtr.p->logMaxGciStarted[twmoIndex]; arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + (2 * ZNO_MBYTES_IN_FILE)) + twmoIndex, ZPAGE_SIZE); logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (twmoLoop * ZFD_PART_SIZE)) + (2 * ZNO_MBYTES_IN_FILE)) + twmoIndex] = wmoLogFilePtr.p->logLastPrepRef[twmoIndex]; }//for wmoLogFilePtr.i = wmoLogFilePtr.p->prevLogFile; twmoLoop = twmoLoop + 1; goto WMO_LOOP; }//if logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = (ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (ZFD_PART_SIZE * twmoNoLogDescriptors); arrGuard(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX], ZPAGE_SIZE); logPagePtr.p->logPageWord[logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]] = ZNEXT_LOG_RECORD_TYPE; /* ------------------------------------------------------- */ /* THIS IS A SPECIAL WRITE OF THE FIRST PAGE IN THE */ /* LOG FILE. THIS HAS SPECIAL SIGNIFANCE TO FIND */ /* THE END OF THE LOG AT SYSTEM RESTART. */ /* ------------------------------------------------------- */ writeSinglePage(signal, 0, ZPAGE_SIZE - 1); if (wmoType == ZINIT) { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_FIRST_PAGE; } else { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE; }//if logFilePtr.p->filePosition = 1; if (wmoType == ZNORMAL) { jam(); /* -------------------------------------------------- */ /* ALLOCATE A NEW PAGE SINCE THE CURRENT IS */ /* WRITTEN. */ /* -------------------------------------------------- */ seizeLogpage(signal); initLogpage(signal); logFilePtr.p->currentLogpage = logPagePtr.i; logFilePtr.p->currentFilepage = logFilePtr.p->currentFilepage + 1; }//if }//Dblqh::writeFileHeaderOpen() /* -------------------------------------------------- */ /* THE NEW FILE POSITION WILL ALWAYS BE 1 SINCE */ /* WE JUST WROTE THE FIRST PAGE IN THE LOG FILE */ /* -------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* ------- WRITE A MBYTE HEADER DURING INITIAL START ------- */ /* */ /* SUBROUTINE SHORT NAME: WIM */ /* ------------------------------------------------------------------------- */ void Dblqh::writeInitMbyte(Signal* signal) { initLogpage(signal); writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, ZPAGE_SIZE - 1); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_INIT_MBYTE; }//Dblqh::writeInitMbyte() /* ------------------------------------------------------------------------- */ /* ------- WRITE A SINGLE PAGE INTO A FILE ------- */ /* */ /* INPUT: TWSP_PAGE_NO THE PAGE NUMBER WRITTEN */ /* SUBROUTINE SHORT NAME: WSP */ /* ------------------------------------------------------------------------- */ void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten) { seizeLfo(signal); initLfo(signal); lfoPtr.p->firstLfoPage = logPagePtr.i; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); lfoPtr.p->lfoPageNo = pageNo; lfoPtr.p->lfoWordWritten = wordWritten; lfoPtr.p->noPagesRw = 1; /* -------------------------------------------------- */ /* SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */ /* LOG RECORD HAS BEEN SENT AT THIS TIME. */ /* -------------------------------------------------- */ logPartPtr.p->logPartTimer = logPartPtr.p->logTimer; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; signal->theData[3] = ZLIST_OF_PAIRS_SYNCH; signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = 1; /* ONE PAGE WRITTEN */ signal->theData[6] = logPagePtr.i; signal->theData[7] = pageNo; sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); }//Dblqh::writeSinglePage() /* ########################################################################## * SYSTEM RESTART PHASE ONE MODULE * THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. * * THIS MODULE CONTAINS THE CODE FOR THE FIRST PHASE OF THE SYSTEM RESTART. * THE AIM OF THIS PHASE IS TO FIND THE END OF THE LOG AND TO FIND * INFORMATION ABOUT WHERE GLOBAL CHECKPOINTS ARE COMPLETED AND STARTED * IN THE LOG. THIS INFORMATION IS NEEDED TO START PHASE THREE OF * THE SYSTEM RESTART. * ########################################################################## */ /* -------------------------------------------------------------------------- * A SYSTEM RESTART OR NODE RESTART IS ONGOING. WE HAVE NOW OPENED FILE 0 * NOW WE NEED TO READ PAGE 0 TO FIND WHICH LOG FILE THAT WAS OPEN AT * CRASH TIME. * -------------------------------------------------------------------------- */ void Dblqh::openSrFrontpageLab(Signal* signal) { readSinglePage(signal, 0); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FRONTPAGE; return; }//Dblqh::openSrFrontpageLab() /* ------------------------------------------------------------------------- * WE HAVE NOW READ PAGE 0 IN FILE 0. CHECK THE LAST OPEN FILE. ACTUALLY THE * LAST OPEN FILE COULD BE THE NEXT AFTER THAT. CHECK THAT FIRST. WHEN THE * LAST WAS FOUND WE CAN FIND ALL THE NEEDED INFORMATION WHERE TO START AND * STOP READING THE LOG. * -------------------------------------------------------------------------- */ void Dblqh::readSrFrontpageLab(Signal* signal) { Uint32 fileNo = logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO]; if (fileNo == 0) { jam(); /* ---------------------------------------------------------------------- * FILE 0 WAS ALSO LAST FILE SO WE DO NOT NEED TO READ IT AGAIN. * ---------------------------------------------------------------------- */ readSrLastFileLab(signal); return; }//if /* ------------------------------------------------------------------------ * CLOSE FILE 0 SO THAT WE HAVE CLOSED ALL FILES WHEN STARTING TO READ * THE FRAGMENT LOG. ALSO RELEASE PAGE ZERO. * ------------------------------------------------------------------------ */ releaseLogpage(signal); logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; closeFile(signal, logFilePtr); LogFileRecordPtr locLogFilePtr; findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_LAST_FILE; openFileRw(signal, locLogFilePtr); return; }//Dblqh::readSrFrontpageLab() void Dblqh::openSrLastFileLab(Signal* signal) { readSinglePage(signal, 0); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_FILE; return; }//Dblqh::openSrLastFileLab() void Dblqh::readSrLastFileLab(Signal* signal) { logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP]; if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { jam(); initGciInLogFileRec(signal, ZMAX_LOG_FILES_IN_PAGE_ZERO); } else { jam(); initGciInLogFileRec(signal, logPartPtr.p->noLogFiles); }//if releaseLogpage(signal); /* ------------------------------------------------------------------------ * NOW WE HAVE FOUND THE LAST LOG FILE. WE ALSO NEED TO FIND THE LAST * MBYTE THAT WAS LAST WRITTEN BEFORE THE SYSTEM CRASH. * ------------------------------------------------------------------------ */ logPartPtr.p->lastLogfile = logFilePtr.i; readSinglePage(signal, 0); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_MBYTE; logFilePtr.p->currentMbyte = 0; return; }//Dblqh::readSrLastFileLab() void Dblqh::readSrLastMbyteLab(Signal* signal) { if (logPartPtr.p->lastMbyte == ZNIL) { if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] < logPartPtr.p->logLap) { jam(); logPartPtr.p->lastMbyte = logFilePtr.p->currentMbyte - 1; }//if }//if arrGuard(logFilePtr.p->currentMbyte, 16); logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] = logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED]; logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] = logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED]; logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF]; releaseLogpage(signal); if (logFilePtr.p->currentMbyte < (ZNO_MBYTES_IN_FILE - 1)) { jam(); logFilePtr.p->currentMbyte++; readSinglePage(signal, ZPAGES_IN_MBYTE * logFilePtr.p->currentMbyte); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_MBYTE; return; } else { jam(); /* ---------------------------------------------------------------------- * THE LOG WAS IN THE LAST MBYTE WHEN THE CRASH OCCURRED SINCE ALL * LOG LAPS ARE EQUAL TO THE CURRENT LOG LAP. * ---------------------------------------------------------------------- */ if (logPartPtr.p->lastMbyte == ZNIL) { jam(); logPartPtr.p->lastMbyte = ZNO_MBYTES_IN_FILE - 1; }//if }//if logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; closeFile(signal, logFilePtr); if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { Uint32 fileNo; if (logFilePtr.p->fileNo >= ZMAX_LOG_FILES_IN_PAGE_ZERO) { jam(); fileNo = logFilePtr.p->fileNo - ZMAX_LOG_FILES_IN_PAGE_ZERO; } else { jam(); fileNo = (logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) - ZMAX_LOG_FILES_IN_PAGE_ZERO; }//if if (fileNo == 0) { jam(); /* -------------------------------------------------------------------- * AVOID USING FILE 0 AGAIN SINCE THAT IS PROBABLY CLOSING AT THE * MOMENT. * -------------------------------------------------------------------- */ fileNo = 1; logPartPtr.p->srRemainingFiles = logPartPtr.p->noLogFiles - (ZMAX_LOG_FILES_IN_PAGE_ZERO - 1); } else { jam(); logPartPtr.p->srRemainingFiles = logPartPtr.p->noLogFiles - ZMAX_LOG_FILES_IN_PAGE_ZERO; }//if LogFileRecordPtr locLogFilePtr; findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE; openFileRw(signal, locLogFilePtr); return; }//if /* ------------------------------------------------------------------------ * THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES. * WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED. * NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE. * ------------------------------------------------------------------------ */ return; }//Dblqh::readSrLastMbyteLab() void Dblqh::openSrNextFileLab(Signal* signal) { readSinglePage(signal, 0); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_NEXT_FILE; return; }//Dblqh::openSrNextFileLab() void Dblqh::readSrNextFileLab(Signal* signal) { if (logPartPtr.p->srRemainingFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { jam(); initGciInLogFileRec(signal, ZMAX_LOG_FILES_IN_PAGE_ZERO); } else { jam(); initGciInLogFileRec(signal, logPartPtr.p->srRemainingFiles); }//if releaseLogpage(signal); logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; closeFile(signal, logFilePtr); if (logPartPtr.p->srRemainingFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { Uint32 fileNo; if (logFilePtr.p->fileNo >= ZMAX_LOG_FILES_IN_PAGE_ZERO) { jam(); fileNo = logFilePtr.p->fileNo - ZMAX_LOG_FILES_IN_PAGE_ZERO; } else { jam(); fileNo = (logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) - ZMAX_LOG_FILES_IN_PAGE_ZERO; }//if if (fileNo == 0) { jam(); /* -------------------------------------------------------------------- * AVOID USING FILE 0 AGAIN SINCE THAT IS PROBABLY CLOSING AT THE MOMENT. * -------------------------------------------------------------------- */ fileNo = 1; logPartPtr.p->srRemainingFiles = logPartPtr.p->srRemainingFiles - (ZMAX_LOG_FILES_IN_PAGE_ZERO - 1); } else { jam(); logPartPtr.p->srRemainingFiles = logPartPtr.p->srRemainingFiles - ZMAX_LOG_FILES_IN_PAGE_ZERO; }//if LogFileRecordPtr locLogFilePtr; findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE; openFileRw(signal, locLogFilePtr); }//if /* ------------------------------------------------------------------------ * THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES. * WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED. * NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE. * ------------------------------------------------------------------------ */ return; }//Dblqh::readSrNextFileLab() void Dblqh::closingSrLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.i = logPartPtr.p->firstLogfile; do { jam(); ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); if (logFilePtr.p->logFileStatus != LogFileRecord::CLOSED) { jam(); /* -------------------------------------------------------------------- * EXIT AND WAIT FOR REMAINING LOG FILES TO COMPLETE THEIR WORK. * -------------------------------------------------------------------- */ return; }//if logFilePtr.i = logFilePtr.p->nextLogFile; } while (logFilePtr.i != logPartPtr.p->firstLogfile); /* ------------------------------------------------------------------------ * ALL FILES IN THIS PART HAVE BEEN CLOSED. THIS INDICATES THAT THE FIRST * PHASE OF THE SYSTEM RESTART HAVE BEEN CONCLUDED FOR THIS LOG PART. * CHECK IF ALL OTHER LOG PARTS ARE ALSO COMPLETED. * ------------------------------------------------------------------------ */ logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED; for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED) { jam(); /* -------------------------------------------------------------------- * EXIT AND WAIT FOR THE REST OF THE LOG PARTS TO COMPLETE. * -------------------------------------------------------------------- */ return; }//if }//for /* ------------------------------------------------------------------------ * THE FIRST PHASE HAVE BEEN COMPLETED. * ------------------------------------------------------------------------ */ signal->theData[0] = ZSR_PHASE3_START; signal->theData[1] = ZSR_PHASE1_COMPLETED; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//Dblqh::closingSrLab() /* ########################################################################## * ####### SYSTEM RESTART PHASE TWO MODULE ####### * * THIS MODULE HANDLES THE SYSTEM RESTART WHERE LQH CONTROLS TUP AND ACC TO * ENSURE THAT THEY HAVE KNOWLEDGE OF ALL FRAGMENTS AND HAVE DONE THE NEEDED * READING OF DATA FROM FILE AND EXECUTION OF LOCAL LOGS. THIS PROCESS * EXECUTES CONCURRENTLY WITH PHASE ONE OF THE SYSTEM RESTART. THIS PHASE * FINDS THE INFORMATION ABOUT THE FRAGMENT LOG NEEDED TO EXECUTE THE FRAGMENT * LOG. * WHEN TUP AND ACC HAVE PREPARED ALL FRAGMENTS THEN LQH ORDERS THOSE LQH'S * THAT ARE RESPONSIBLE TO EXECUTE THE FRAGMENT LOGS TO DO SO. IT IS POSSIBLE * THAT ANOTHER NODE EXECUTES THE LOG FOR A FRAGMENT RESIDING AT THIS NODE. * ########################################################################## */ /* ***************>> */ /* START_FRAGREQ > */ /* ***************>> */ void Dblqh::execSTART_FRAGREQ(Signal* signal) { const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; jamEntry(); tabptr.i = startFragReq->tableId; Uint32 fragId = startFragReq->fragId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); if (!getFragmentrec(signal, fragId)) { startFragRefLab(signal); return; }//if tabptr.p->tableStatus = Tablerec::TABLE_DEFINED; initFragrecSr(signal); if (startFragReq->lcpNo == ZNIL) { jam(); /* ---------------------------------------------------------------------- * THERE WAS NO LOCAL CHECKPOINT AVAILABLE FOR THIS FRAGMENT. WE DO * NOT NEED TO READ IN THE LOCAL FRAGMENT. WE HAVE ALREADY ADDED THE * FRAGMENT AS AN EMPTY FRAGMENT AT THIS POINT. THUS WE CAN SIMPLY * EXIT AND THE FRAGMENT WILL PARTICIPATE IN THE EXECUTION OF THE LOG. * PUT FRAGMENT ON LIST OF COMPLETED FRAGMENTS FOR EXECUTION OF LOG. * ---------------------------------------------------------------------- */ fragptr.p->nextFrag = cfirstCompletedFragSr; cfirstCompletedFragSr = fragptr.i; return; }//if if (cfirstWaitFragSr == RNIL) { jam(); lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { jam(); initLcpSr(signal, startFragReq->lcpNo, startFragReq->lcpId, tabptr.i, fragId, fragptr.i); signal->theData[0] = lcpPtr.i; signal->theData[1] = cownref; signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; sendSignal(fragptr.p->accBlockref, GSN_SR_FRAGIDREQ, signal, 5, JBB); return; }//if }//if fragptr.p->nextFrag = cfirstWaitFragSr; cfirstWaitFragSr = fragptr.i; }//Dblqh::execSTART_FRAGREQ() void Dblqh::startFragRefLab(Signal* signal) { const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; BlockReference userRef = startFragReq->userRef; Uint32 userPtr = startFragReq->userPtr; signal->theData[0] = userPtr; signal->theData[1] = terrorCode; signal->theData[2] = cownNodeid; sendSignal(userRef, GSN_START_FRAGREF, signal, 3, JBB); return; }//Dblqh::startFragRefLab() /* ***************>> */ /* SR_FRAGIDCONF > */ /* ***************>> */ /* -------------------------------------------------------------------------- * PRECONDITION: LCP_PTR:LCP_STATE = SR_WAIT_FRAGID * -------------------------------------------------------------------------- */ void Dblqh::execSR_FRAGIDCONF(Signal* signal) { SrFragidConf * const srFragidConf = (SrFragidConf *)&signal->theData[0]; jamEntry(); lcpPtr.i = srFragidConf->lcpPtr; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_SR_WAIT_FRAGID); /* ------------------------------------------------------------------------ * NO ERROR CHECKING OF TNO_LOCFRAG VALUE. OUT OF BOUND WILL IMPLY THAT AN * INDEX OUT OF RANGE WILL CAUSE A SYSTEM RESTART WHICH IS DESIRED. * ------------------------------------------------------------------------ */ lcpPtr.p->lcpAccptr = srFragidConf->accPtr; fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->accFragptr[0] = srFragidConf->fragPtr[0]; fragptr.p->accFragptr[1] = srFragidConf->fragPtr[1]; fragptr.p->hashCheckBit = srFragidConf->hashCheckBit; Uint32 noLocFrag = srFragidConf->noLocFrag; ndbrequire(noLocFrag == 2); Uint32 fragid[2]; Uint32 i; for (i = 0; i < noLocFrag; i++) { fragid[i] = srFragidConf->fragId[i]; }//for for (i = 0; i < noLocFrag; i++) { jam(); Uint32 fragId = fragid[i]; /* ---------------------------------------------------------------------- * THERE IS NO ERROR CHECKING ON PURPOSE. IT IS POSSIBLE TO CALCULATE HOW * MANY LOCAL LCP RECORDS THERE SHOULD BE. IT SHOULD NEVER HAPPEN THAT * THERE IS NO ONE FREE. IF THERE IS NO ONE IT WILL ALSO BE A POINTER * OUT OF RANGE WHICH IS AN ERROR CODE IN ITSELF. REUSES ERROR * HANDLING IN AXE VM. * ---------------------------------------------------------------------- */ seizeLcpLoc(signal); initLcpLocAcc(signal, fragId); lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_ACC_STARTED; signal->theData[0] = lcpPtr.p->lcpAccptr; signal->theData[1] = lcpLocptr.i; signal->theData[2] = lcpLocptr.p->locFragid; signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; sendSignal(fragptr.p->accBlockref, GSN_ACC_SRREQ, signal, 4, JBB); seizeLcpLoc(signal); initLcpLocTup(signal, fragId); lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_TUP_STARTED; signal->theData[0] = lcpLocptr.i; signal->theData[1] = cownref; signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; signal->theData[3] = lcpLocptr.p->locFragid; signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; sendSignal(fragptr.p->tupBlockref, GSN_TUP_SRREQ, signal, 5, JBB); }//for lcpPtr.p->lcpState = LcpRecord::LCP_SR_STARTED; return; }//Dblqh::execSR_FRAGIDCONF() /* ***************> */ /* SR_FRAGIDREF > */ /* ***************> */ void Dblqh::execSR_FRAGIDREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execSR_FRAGIDREF() /* ************>> */ /* ACC_SRCONF > */ /* ************>> */ /* -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = SR_ACC_STARTED * -------------------------------------------------------------------------- */ void Dblqh::execACC_SRCONF(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (lcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { jam(); systemErrorLab(signal); return; }//if lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ------------------------------------------------------------------------ */ lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_ACC_COMPLETED; srCompletedLab(signal); return; }//Dblqh::execACC_SRCONF() /* ************> */ /* ACC_SRREF > */ /* ************> */ void Dblqh::execACC_SRREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; systemErrorLab(signal); return; }//Dblqh::execACC_SRREF() /* ************>> */ /* TUP_SRCONF > */ /* ************>> */ /* -------------------------------------------------------------------------- * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = SR_TUP_STARTED * -------------------------------------------------------------------------- */ void Dblqh::execTUP_SRCONF(Signal* signal) { jamEntry(); lcpLocptr.i = signal->theData[0]; ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); Uint32 tupFragPtr = signal->theData[1]; ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::SR_TUP_STARTED); lcpPtr.i = lcpLocptr.p->masterLcpRec; ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); /* ------------------------------------------------------------------------ * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. * ------------------------------------------------------------------------ */ lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_TUP_COMPLETED; fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (lcpLocptr.i == lcpPtr.p->firstLcpLocTup) { jam(); fragptr.p->tupFragptr[1] = tupFragPtr; } else { jam(); fragptr.p->tupFragptr[0] = tupFragPtr; }//if srCompletedLab(signal); return; }//Dblqh::execTUP_SRCONF() void Dblqh::srCompletedLab(Signal* signal) { checkSrCompleted(signal); if (lcpPtr.p->lcpState == LcpRecord::LCP_SR_COMPLETED) { jam(); /* ---------------------------------------------------------------------- * THE SYSTEM RESTART OF THIS FRAGMENT HAS BEEN COMPLETED. IT IS NOW * TIME TO START A SYSTEM RESTART ON THE NEXT FRAGMENT OR CONTINUE * WITH THE NEXT STEP OF THE SYSTEM RESTART. THIS STEP IS TO EXECUTE * THE FRAGMENT LOGS. * ---------------------------------------------------------------------- * WE RELEASE THE LOCAL LCP RECORDS. * --------------------------------------------------------------------- */ releaseLocalLcps(signal); /* ---------------------------------------------------------------------- * PUT FRAGMENT ON LIST OF FRAGMENTS WHICH HAVE BEEN STARTED AS PART OF * THE SYSTEM RESTART. THEY ARE NOW WAITING TO EXECUTE THE FRAGMENT LOG. * --------------------------------------------------------------------- */ fragptr.i = lcpPtr.p->currentFragment.fragPtrI; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->nextFrag = cfirstCompletedFragSr; cfirstCompletedFragSr = fragptr.i; if (cfirstWaitFragSr != RNIL) { jam(); /* -------------------------------------------------------------------- * ANOTHER FRAGMENT IS WAITING FOR SYSTEM RESTART. RESTART THIS * FRAGMENT AS WELL. * -------------------------------------------------------------------- */ fragptr.i = cfirstWaitFragSr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); cfirstWaitFragSr = fragptr.p->nextFrag; /* -------------------------------------------------------------------- * RETRIEVE DATA FROM THE FRAGMENT RECORD. * -------------------------------------------------------------------- */ ndbrequire(fragptr.p->srChkpnr < MAX_LCP_STORED); initLcpSr(signal, fragptr.p->srChkpnr, fragptr.p->lcpId[fragptr.p->srChkpnr], fragptr.p->tabRef, fragptr.p->fragId, fragptr.i); signal->theData[0] = lcpPtr.i; signal->theData[1] = cownref; signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; sendSignal(fragptr.p->accBlockref, GSN_SR_FRAGIDREQ, signal, 5, JBB); return; } else { jam(); /* -------------------------------------------------------------------- * NO MORE FRAGMENTS ARE WAITING FOR SYSTEM RESTART. * -------------------------------------------------------------------- */ lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; if (cstartRecReq == ZTRUE) { jam(); /* ---------------------------------------------------------------- * WE HAVE ALSO RECEIVED AN INDICATION THAT NO MORE FRAGMENTS * NEEDS RESTART. * NOW IT IS TIME TO START EXECUTING THE UNDO LOG. * ---------------------------------------------------------------- * WE ARE NOW IN A POSITION TO ORDER TUP AND ACC TO START * EXECUTING THEIR UNDO LOGS. THIS MUST BE DONE BEFORE THE * FRAGMENT LOGS CAN BE EXECUTED. * ---------------------------------------------------------------- */ csrExecUndoLogState = EULS_STARTED; signal->theData[0] = caccBlockref; signal->theData[1] = cownref; sendSignal(caccBlockref, GSN_START_RECREQ, signal, 2, JBB); signal->theData[0] = ctupBlockref; signal->theData[1] = cownref; sendSignal(ctupBlockref, GSN_START_RECREQ, signal, 2, JBB); return; } else { jam(); /* ---------------------------------------------------------------- * WE HAVE NOT RECEIVED ALL FRAGMENTS YET OR AT LEAST NOT WE * HAVE NOT RECEIVED THE START_RECREQ SIGNAL. EXIT AND WAIT * FOR MORE. * ---------------------------------------------------------------- */ return; }//if }//if }//if /*---------------*/ /* ELSE */ /*------------------------------------------------------------------------- * THE SYSTEM RESTART ON THIS FRAGMENT HAS NOT BEEN COMPLETED, * EXIT AND WAIT FOR MORE SIGNALS *------------------------------------------------------------------------- * DO NOTHING, EXIT IS EXECUTED BELOW *------------------------------------------------------------------------- */ return; }//Dblqh::srCompletedLab() /* ************> */ /* TUP_SRREF > */ /* ************> */ void Dblqh::execTUP_SRREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; systemErrorLab(signal); return; }//Dblqh::execTUP_SRREF() /* ***************> */ /* START_RECREQ > */ /* ***************> */ void Dblqh::execSTART_RECREQ(Signal* signal) { CRASH_INSERTION(5027); jamEntry(); StartRecReq * const req = (StartRecReq*)&signal->theData[0]; cmasterDihBlockref = req->senderRef; crestartOldestGci = req->keepGci; crestartNewestGci = req->lastCompletedGci; cnewestGci = req->newestGci; ndbrequire(req->receivingNodeId == cownNodeid); cnewestCompletedGci = cnewestGci; cstartRecReq = ZTRUE; for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { ptrAss(logPartPtr, logPartRecord); logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; }//for /* ------------------------------------------------------------------------ * WE HAVE TO SET THE OLDEST AND THE NEWEST GLOBAL CHECKPOINT IDENTITY * THAT WILL SURVIVE THIS SYSTEM RESTART. THIS IS NEEDED SO THAT WE CAN * SET THE LOG HEAD AND LOG TAIL PROPERLY BEFORE STARTING THE SYSTEM AGAIN. * WE ALSO NEED TO SET CNEWEST_GCI TO ENSURE THAT LOG RECORDS ARE EXECUTED * WITH A PROPER GCI. *------------------------------------------------------------------------ */ if (cstartType == NodeState::ST_NODE_RESTART) { jam(); signal->theData[0] = ZSR_PHASE3_START; signal->theData[1] = ZSR_PHASE2_COMPLETED; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//if if(cstartType == NodeState::ST_INITIAL_NODE_RESTART){ jam(); StartRecConf * conf = (StartRecConf*)signal->getDataPtrSend(); conf->startingNodeId = getOwnNodeId(); sendSignal(cmasterDihBlockref, GSN_START_RECCONF, signal, StartRecConf::SignalLength, JBB); return; }//if if (cfirstWaitFragSr == RNIL) { /* ---------------------------------------------------------------------- * THERE ARE NO FRAGMENTS WAITING TO BE RESTARTED. * --------------------------------------------------------------------- */ lcpPtr.i = 0; ptrAss(lcpPtr, lcpRecord); if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { jam(); /* -------------------------------------------------------------------- * THERE ARE NO FRAGMENTS THAT ARE CURRENTLY PERFORMING THEIR * SYSTEM RESTART. * -------------------------------------------------------------------- * WE ARE NOW IN A POSITION TO ORDER TUP AND ACC TO START EXECUTING * THEIR UNDO LOGS. THIS MUST BE DONE BEFORE THE FRAGMENT LOGS * CAN BE EXECUTED. * ------------------------------------------------------------------- */ csrExecUndoLogState = EULS_STARTED; signal->theData[0] = caccBlockref; signal->theData[1] = cownref; sendSignal(caccBlockref, GSN_START_RECREQ, signal, 2, JBB); signal->theData[0] = ctupBlockref; signal->theData[1] = cownref; sendSignal(ctupBlockref, GSN_START_RECREQ, signal, 2, JBB); }//if }//if /* ----------------------------------------------------------------------- * EXIT AND WAIT FOR COMPLETION OF ALL FRAGMENTS. * ----------------------------------------------------------------------- */ return; }//Dblqh::execSTART_RECREQ() /* ***************>> */ /* START_RECCONF > */ /* ***************>> */ void Dblqh::execSTART_RECCONF(Signal* signal) { jamEntry(); BlockReference userRef = signal->theData[0]; if (userRef == caccBlockref) { if (csrExecUndoLogState == EULS_STARTED) { jam(); csrExecUndoLogState = EULS_ACC_COMPLETED; } else { ndbrequire(csrExecUndoLogState == EULS_TUP_COMPLETED); jam(); csrExecUndoLogState = EULS_COMPLETED; /* -------------------------------------------------------------------- * START THE FIRST PHASE OF EXECUTION OF THE LOG. * ------------------------------------------------------------------- */ startExecSr(signal); }//if } else { ndbrequire(userRef == ctupBlockref); if (csrExecUndoLogState == EULS_STARTED) { jam(); csrExecUndoLogState = EULS_TUP_COMPLETED; } else { ndbrequire(csrExecUndoLogState == EULS_ACC_COMPLETED); jam(); csrExecUndoLogState = EULS_COMPLETED; /* -------------------------------------------------------------------- * START THE FIRST PHASE OF EXECUTION OF THE LOG. * ------------------------------------------------------------------- */ startExecSr(signal); }//if }//if return; }//Dblqh::execSTART_RECCONF() /* ***************> */ /* START_RECREF > */ /* ***************> */ void Dblqh::execSTART_RECREF(Signal* signal) { jamEntry(); ndbrequire(false); }//Dblqh::execSTART_RECREF() /* ***************>> */ /* START_EXEC_SR > */ /* ***************>> */ void Dblqh::execSTART_EXEC_SR(Signal* signal) { FragrecordPtr prevFragptr; jamEntry(); fragptr.i = signal->theData[0]; prevFragptr.i = signal->theData[1]; if (fragptr.i == RNIL) { jam(); ndbrequire(cnoOfNodes < MAX_NDB_NODES); /* ---------------------------------------------------------------------- * NO MORE FRAGMENTS TO START EXECUTING THE LOG ON. * SEND EXEC_SRREQ TO ALL LQH TO INDICATE THAT THIS NODE WILL * NOT REQUEST ANY MORE FRAGMENTS TO EXECUTE THE FRAGMENT LOG ON. * ---------------------------------------------------------------------- * WE NEED TO SEND THOSE SIGNALS EVEN IF WE HAVE NOT REQUESTED * ANY FRAGMENTS PARTICIPATE IN THIS PHASE. * --------------------------------------------------------------------- */ for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); if (cnodeStatus[i] == ZNODE_UP) { jam(); ndbrequire(cnodeData[i] < MAX_NDB_NODES); BlockReference ref = calcLqhBlockRef(cnodeData[i]); signal->theData[0] = cownNodeid; sendSignal(ref, GSN_EXEC_SRREQ, signal, 1, JBB); }//if }//for } else { jam(); ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (fragptr.p->srNoLognodes > csrPhasesCompleted) { jam(); Uint32 index = csrPhasesCompleted; arrGuard(index, 4); BlockReference ref = calcLqhBlockRef(fragptr.p->srLqhLognode[index]); fragptr.p->srStatus = Fragrecord::SS_STARTED; /* -------------------------------------------------------------------- * SINCE WE CAN HAVE SEVERAL LQH NODES PER FRAGMENT WE CALCULATE * THE LQH POINTER IN SUCH A WAY THAT WE CAN DEDUCE WHICH OF THE * LQH NODES THAT HAS RESPONDED WHEN EXEC_FRAGCONF IS RECEIVED. * ------------------------------------------------------------------- */ ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; execFragReq->userPtr = fragptr.i; execFragReq->userRef = cownref; execFragReq->tableId = fragptr.p->tabRef; execFragReq->fragId = fragptr.p->fragId; execFragReq->startGci = fragptr.p->srStartGci[index]; execFragReq->lastGci = fragptr.p->srLastGci[index]; sendSignal(ref, GSN_EXEC_FRAGREQ, signal, ExecFragReq::SignalLength, JBB); prevFragptr.i = fragptr.i; fragptr.i = fragptr.p->nextFrag; } else { jam(); /* -------------------------------------------------------------------- * THIS FRAGMENT IS NOW FINISHED WITH THE SYSTEM RESTART. IT DOES * NOT NEED TO PARTICIPATE IN ANY MORE PHASES. REMOVE IT FROM THE * LIST OF COMPLETED FRAGMENTS TO EXECUTE THE LOG ON. * ALSO SEND START_FRAGCONF TO DIH AND SET THE STATE TO ACTIVE ON THE * FRAGMENT. * ------------------------------------------------------------------- */ Uint32 next = fragptr.p->nextFrag; if (prevFragptr.i != RNIL) { jam(); ptrCheckGuard(prevFragptr, cfragrecFileSize, fragrecord); prevFragptr.p->nextFrag = next; } else { jam(); cfirstCompletedFragSr = next; }//if /** * Put fragment on list which has completed REDO log */ fragptr.p->nextFrag = c_redo_log_complete_frags; c_redo_log_complete_frags = fragptr.i; fragptr.p->fragStatus = Fragrecord::FSACTIVE; fragptr.p->logFlag = Fragrecord::STATE_TRUE; signal->theData[0] = fragptr.p->srUserptr; signal->theData[1] = cownNodeid; sendSignal(fragptr.p->srBlockref, GSN_START_FRAGCONF, signal, 2, JBB); /* -------------------------------------------------------------------- * WE HAVE TO ENSURE THAT THIS FRAGMENT IS NOT PUT BACK ON THE LIST BY * MISTAKE. WE DO THIS BY ALSO REMOVING IT AS PREVIOUS IN START_EXEC_SR * THIS IS PERFORMED BY KEEPING PREV_FRAGPTR AS PREV_FRAGPTR BUT MOVING * FRAGPTR TO THE NEXT FRAGMENT IN THE LIST. * ------------------------------------------------------------------- */ fragptr.i = next; }//if signal->theData[0] = fragptr.i; signal->theData[1] = prevFragptr.i; sendSignal(cownref, GSN_START_EXEC_SR, signal, 2, JBB); }//if return; }//Dblqh::execSTART_EXEC_SR() /* ***************> */ /* EXEC_FRAGREQ > */ /* ***************> */ /* -------------------------------------------------------------------------- * THIS SIGNAL IS USED TO REQUEST THAT A FRAGMENT PARTICIPATES IN EXECUTING * THE LOG IN THIS NODE. * ------------------------------------------------------------------------- */ void Dblqh::execEXEC_FRAGREQ(Signal* signal) { ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; jamEntry(); tabptr.i = execFragReq->tableId; Uint32 fragId = execFragReq->fragId; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); if (!getFragmentrec(signal, fragId)) { jam(); if (!insertFragrec(signal, fragId)) { jam(); sendExecFragRefLab(signal); return; }//if initFragrec(signal, tabptr.i, fragId, ZLOG_NODE); fragptr.p->execSrStatus = Fragrecord::ACTIVE_REMOVE_AFTER; } else { jam(); if (fragptr.p->execSrStatus == Fragrecord::ACTIVE_REMOVE_AFTER) { jam(); fragptr.p->execSrStatus = Fragrecord::ACTIVE_REMOVE_AFTER; } else { jam(); }//if }//if ndbrequire(fragptr.p->execSrNoReplicas < 4); fragptr.p->execSrBlockref[fragptr.p->execSrNoReplicas] = execFragReq->userRef; fragptr.p->execSrUserptr[fragptr.p->execSrNoReplicas] = execFragReq->userPtr; fragptr.p->execSrStartGci[fragptr.p->execSrNoReplicas] = execFragReq->startGci; fragptr.p->execSrLastGci[fragptr.p->execSrNoReplicas] = execFragReq->lastGci; fragptr.p->execSrStatus = Fragrecord::ACTIVE; fragptr.p->execSrNoReplicas++; cnoFragmentsExecSr++; return; }//Dblqh::execEXEC_FRAGREQ() void Dblqh::sendExecFragRefLab(Signal* signal) { ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; BlockReference retRef = execFragReq->userRef; Uint32 retPtr = execFragReq->userPtr; signal->theData[0] = retPtr; signal->theData[1] = terrorCode; sendSignal(retRef, GSN_EXEC_FRAGREF, signal, 2, JBB); return; }//Dblqh::sendExecFragRefLab() /* ***************>> */ /* EXEC_FRAGCONF > */ /* ***************>> */ void Dblqh::execEXEC_FRAGCONF(Signal* signal) { jamEntry(); fragptr.i = signal->theData[0]; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->srStatus = Fragrecord::SS_COMPLETED; return; }//Dblqh::execEXEC_FRAGCONF() /* ***************> */ /* EXEC_FRAGREF > */ /* ***************> */ void Dblqh::execEXEC_FRAGREF(Signal* signal) { jamEntry(); terrorCode = signal->theData[1]; systemErrorLab(signal); return; }//Dblqh::execEXEC_FRAGREF() /* *************** */ /* EXEC_SRCONF > */ /* *************** */ void Dblqh::execEXEC_SRCONF(Signal* signal) { jamEntry(); Uint32 nodeId = signal->theData[0]; arrGuard(nodeId, MAX_NDB_NODES); cnodeExecSrState[nodeId] = ZEXEC_SR_COMPLETED; ndbrequire(cnoOfNodes < MAX_NDB_NODES); for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); if (cnodeStatus[i] == ZNODE_UP) { jam(); nodeId = cnodeData[i]; arrGuard(nodeId, MAX_NDB_NODES); if (cnodeExecSrState[nodeId] != ZEXEC_SR_COMPLETED) { jam(); /* ------------------------------------------------------------------ * ALL NODES HAVE NOT REPORTED COMPLETION OF EXECUTING FRAGMENT * LOGS YET. * ----------------------------------------------------------------- */ return; }//if }//if }//for /* ------------------------------------------------------------------------ * CLEAR NODE SYSTEM RESTART EXECUTION STATE TO PREPARE FOR NEXT PHASE OF * LOG EXECUTION. * ----------------------------------------------------------------------- */ for (nodeId = 0; nodeId < MAX_NDB_NODES; nodeId++) { cnodeExecSrState[nodeId] = ZSTART_SR; }//for /* ------------------------------------------------------------------------ * NOW CHECK IF ALL FRAGMENTS IN THIS PHASE HAVE COMPLETED. IF SO START THE * NEXT PHASE. * ----------------------------------------------------------------------- */ fragptr.i = cfirstCompletedFragSr; if (fragptr.i == RNIL) { jam(); execSrCompletedLab(signal); return; }//if do { jam(); ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); ndbrequire(fragptr.p->srStatus == Fragrecord::SS_COMPLETED); fragptr.i = fragptr.p->nextFrag; } while (fragptr.i != RNIL); execSrCompletedLab(signal); return; }//Dblqh::execEXEC_SRCONF() void Dblqh::execSrCompletedLab(Signal* signal) { csrPhasesCompleted++; /* ------------------------------------------------------------------------ * ALL FRAGMENTS WERE COMPLETED. THIS PHASE IS COMPLETED. IT IS NOW TIME TO * START THE NEXT PHASE. * ----------------------------------------------------------------------- */ if (csrPhasesCompleted >= 4) { jam(); /* ---------------------------------------------------------------------- * THIS WAS THE LAST PHASE. WE HAVE NOW COMPLETED THE EXECUTION THE * FRAGMENT LOGS IN ALL NODES. BEFORE WE SEND START_RECCONF TO THE * MASTER DIH TO INDICATE A COMPLETED SYSTEM RESTART IT IS NECESSARY * TO FIND THE HEAD AND THE TAIL OF THE LOG WHEN NEW OPERATIONS START * TO COME AGAIN. * * THE FIRST STEP IS TO FIND THE HEAD AND TAIL MBYTE OF EACH LOG PART. * TO DO THIS WE REUSE THE CONTINUEB SIGNAL SR_LOG_LIMITS. THEN WE * HAVE TO FIND THE ACTUAL PAGE NUMBER AND PAGE INDEX WHERE TO * CONTINUE WRITING THE LOG AFTER THE SYSTEM RESTART. * --------------------------------------------------------------------- */ for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED; logPartPtr.p->logLastGci = crestartNewestGci; logPartPtr.p->logStartGci = crestartOldestGci; logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP; if (logPartPtr.p->headFileNo == ZNIL) { jam(); /* ----------------------------------------------------------------- * IF WE HAVEN'T FOUND ANY HEAD OF THE LOG THEN WE ARE IN SERIOUS * PROBLEM. THIS SHOULD NOT OCCUR. IF IT OCCURS ANYWAY THEN WE * HAVE TO FIND A CURE FOR THIS PROBLEM. * ----------------------------------------------------------------- */ systemErrorLab(signal); return; }//if signal->theData[0] = ZSR_LOG_LIMITS; signal->theData[1] = logPartPtr.i; signal->theData[2] = logPartPtr.p->lastLogfile; signal->theData[3] = logPartPtr.p->lastMbyte; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); }//for return; } else { jam(); /* ---------------------------------------------------------------------- * THERE ARE YET MORE PHASES TO RESTART. * WE MUST INITIALISE DATA FOR NEXT PHASE AND SEND START SIGNAL. * --------------------------------------------------------------------- */ startExecSr(signal); }//if return; }//Dblqh::execSrCompletedLab() /* ************>> */ /* EXEC_SRREQ > */ /* ************>> */ void Dblqh::execEXEC_SRREQ(Signal* signal) { jamEntry(); Uint32 nodeId = signal->theData[0]; ndbrequire(nodeId < MAX_NDB_NODES); cnodeSrState[nodeId] = ZEXEC_SR_COMPLETED; ndbrequire(cnoOfNodes < MAX_NDB_NODES); for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); if (cnodeStatus[i] == ZNODE_UP) { jam(); nodeId = cnodeData[i]; if (cnodeSrState[nodeId] != ZEXEC_SR_COMPLETED) { jam(); /* ------------------------------------------------------------------ * ALL NODES HAVE NOT REPORTED COMPLETION OF SENDING EXEC_FRAGREQ YET. * ----------------------------------------------------------------- */ return; }//if }//if }//for /* ------------------------------------------------------------------------ * CLEAR NODE SYSTEM RESTART STATE TO PREPARE FOR NEXT PHASE OF LOG * EXECUTION * ----------------------------------------------------------------------- */ for (nodeId = 0; nodeId < MAX_NDB_NODES; nodeId++) { cnodeSrState[nodeId] = ZSTART_SR; }//for if (csrPhasesCompleted != 0) { /* ---------------------------------------------------------------------- * THE FIRST PHASE MUST ALWAYS EXECUTE THE LOG. * --------------------------------------------------------------------- */ if (cnoFragmentsExecSr == 0) { jam(); /* -------------------------------------------------------------------- * THERE WERE NO FRAGMENTS THAT NEEDED TO EXECUTE THE LOG IN THIS PHASE. * ------------------------------------------------------------------- */ srPhase3Comp(signal); return; }//if }//if /* ------------------------------------------------------------------------ * NOW ALL NODES HAVE SENT ALL EXEC_FRAGREQ. NOW WE CAN START EXECUTING THE * LOG FROM THE MINIMUM GCI NEEDED UNTIL THE MAXIMUM GCI NEEDED. * * WE MUST FIRST CHECK IF THE FIRST PHASE OF THE SYSTEM RESTART HAS BEEN * COMPLETED. THIS HANDLING IS PERFORMED IN THE FILE SYSTEM MODULE * ----------------------------------------------------------------------- */ signal->theData[0] = ZSR_PHASE3_START; signal->theData[1] = ZSR_PHASE2_COMPLETED; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//Dblqh::execEXEC_SRREQ() /* ######################################################################### */ /* SYSTEM RESTART PHASE THREE MODULE */ /* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ /* */ /* THIS MODULE IS CONCERNED WITH EXECUTING THE FRAGMENT LOG. IT DOES ALSO */ /* CONTAIN SIGNAL RECEPTIONS LQHKEYCONF AND LQHKEYREF SINCE LQHKEYREQ IS USED*/ /* TO EXECUTE THE LOG RECORDS. */ /* */ /* BEFORE IT STARTS IT HAS BEEN DECIDED WHERE TO START AND WHERE TO STOP */ /* READING THE FRAGMENT LOG BY USING THE INFORMATION ABOUT GCI DISCOVERED IN */ /* PHASE ONE OF THE SYSTEM RESTART. */ /* ######################################################################### */ /*---------------------------------------------------------------------------*/ /* PHASE THREE OF THE SYSTEM RESTART CAN NOW START. ONE OF THE PHASES HAVE */ /* COMPLETED. */ /*---------------------------------------------------------------------------*/ void Dblqh::srPhase3Start(Signal* signal) { UintR tsrPhaseStarted; jamEntry(); tsrPhaseStarted = signal->theData[0]; if (csrPhaseStarted == ZSR_NO_PHASE_STARTED) { jam(); csrPhaseStarted = tsrPhaseStarted; if (cstartType == NodeState::ST_NODE_RESTART) { ndbrequire(cinitialStartOngoing == ZTRUE); cinitialStartOngoing = ZFALSE; checkStartCompletedLab(signal); }//if return; }//if ndbrequire(csrPhaseStarted != tsrPhaseStarted); ndbrequire(csrPhaseStarted != ZSR_BOTH_PHASES_STARTED); csrPhaseStarted = ZSR_BOTH_PHASES_STARTED; for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_STARTED; logPartPtr.p->logStartGci = (UintR)-1; if (csrPhasesCompleted == 0) { jam(); /* -------------------------------------------------------------------- * THE FIRST PHASE WE MUST ENSURE THAT IT REACHES THE END OF THE LOG. * ------------------------------------------------------------------- */ logPartPtr.p->logLastGci = crestartNewestGci; } else { jam(); logPartPtr.p->logLastGci = 2; }//if }//for if (cstartType == NodeState::ST_NODE_RESTART) { jam(); /* ---------------------------------------------------------------------- * FOR A NODE RESTART WE HAVE NO FRAGMENTS DEFINED YET. * THUS WE CAN SKIP THAT PART * --------------------------------------------------------------------- */ signal->theData[0] = ZSR_GCI_LIMITS; signal->theData[1] = RNIL; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); } else { jam(); signal->theData[0] = ZSR_GCI_LIMITS; signal->theData[1] = 0; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if return; }//Dblqh::srPhase3Start() /* -------------------------------------------------------------------------- * WE NOW WE NEED TO FIND THE LIMITS WITHIN WHICH TO EXECUTE * THE FRAGMENT LOG * ------------------------------------------------------------------------- */ void Dblqh::srGciLimits(Signal* signal) { LogPartRecordPtr tmpLogPartPtr; jamEntry(); fragptr.i = signal->theData[0]; Uint32 loopCount = 0; logPartPtr.i = 0; ptrAss(logPartPtr, logPartRecord); while (fragptr.i < cfragrecFileSize) { jam(); ptrAss(fragptr, fragrecord); if (fragptr.p->execSrStatus != Fragrecord::IDLE) { jam(); ndbrequire(fragptr.p->execSrNoReplicas - 1 < 4); for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) { jam(); if (fragptr.p->execSrStartGci[i] < logPartPtr.p->logStartGci) { jam(); logPartPtr.p->logStartGci = fragptr.p->execSrStartGci[i]; }//if if (fragptr.p->execSrLastGci[i] > logPartPtr.p->logLastGci) { jam(); logPartPtr.p->logLastGci = fragptr.p->execSrLastGci[i]; }//if }//for }//if loopCount++; if (loopCount > 20) { jam(); signal->theData[0] = ZSR_GCI_LIMITS; signal->theData[1] = fragptr.i + 1; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; } else { jam(); fragptr.i++; }//if }//while if (logPartPtr.p->logStartGci == (UintR)-1) { jam(); /* -------------------------------------------------------------------- * THERE WERE NO FRAGMENTS TO INSTALL WE WILL EXECUTE THE LOG AS * SHORT AS POSSIBLE TO REACH THE END OF THE LOG. THIS WE DO BY * STARTING AT THE STOP GCI. * ------------------------------------------------------------------- */ logPartPtr.p->logStartGci = logPartPtr.p->logLastGci; }//if for (tmpLogPartPtr.i = 1; tmpLogPartPtr.i < 4; tmpLogPartPtr.i++) { ptrAss(tmpLogPartPtr, logPartRecord); tmpLogPartPtr.p->logStartGci = logPartPtr.p->logStartGci; tmpLogPartPtr.p->logLastGci = logPartPtr.p->logLastGci; }//for for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP; signal->theData[0] = ZSR_LOG_LIMITS; signal->theData[1] = logPartPtr.i; signal->theData[2] = logPartPtr.p->lastLogfile; signal->theData[3] = logPartPtr.p->lastMbyte; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); }//for }//Dblqh::srGciLimits() /* -------------------------------------------------------------------------- * IT IS NOW TIME TO FIND WHERE TO START EXECUTING THE LOG. * THIS SIGNAL IS SENT FOR EACH LOG PART AND STARTS THE EXECUTION * OF THE LOG FOR THIS PART. *-------------------------------------------------------------------------- */ void Dblqh::srLogLimits(Signal* signal) { Uint32 tlastPrepRef; Uint32 tmbyte; jamEntry(); logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.i = signal->theData[1]; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); tmbyte = signal->theData[2]; Uint32 loopCount = 0; /* ------------------------------------------------------------------------ * WE ARE SEARCHING FOR THE START AND STOP MBYTE OF THE LOG THAT IS TO BE * EXECUTED. * ----------------------------------------------------------------------- */ while(true) { ndbrequire(tmbyte < 16); if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_STOP) { if (logFilePtr.p->logMaxGciCompleted[tmbyte] < logPartPtr.p->logLastGci) { jam(); /* -------------------------------------------------------------------- * WE ARE STEPPING BACKWARDS FROM MBYTE TO MBYTE. THIS IS THE FIRST * MBYTE WHICH IS TO BE INCLUDED IN THE LOG EXECUTION. THE STOP GCI * HAS NOT BEEN COMPLETED BEFORE THIS MBYTE. THUS THIS MBYTE HAVE * TO BE EXECUTED. * ------------------------------------------------------------------- */ logPartPtr.p->stopLogfile = logFilePtr.i; logPartPtr.p->stopMbyte = tmbyte; logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_START; }//if }//if /* ------------------------------------------------------------------------ * WHEN WE HAVEN'T FOUND THE STOP MBYTE IT IS NOT NECESSARY TO LOOK FOR THE * START MBYTE. THE REASON IS THE FOLLOWING LOGIC CHAIN: * MAX_GCI_STARTED >= MAX_GCI_COMPLETED >= LAST_GCI >= START_GCI * THUS MAX_GCI_STARTED >= START_GCI. THUS MAX_GCI_STARTED < START_GCI CAN * NOT BE TRUE AS WE WILL CHECK OTHERWISE. * ----------------------------------------------------------------------- */ if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_START) { if (logFilePtr.p->logMaxGciStarted[tmbyte] < logPartPtr.p->logStartGci) { jam(); /* -------------------------------------------------------------------- * WE HAVE NOW FOUND THE START OF THE EXECUTION OF THE LOG. * WE STILL HAVE TO MOVE IT BACKWARDS TO ALSO INCLUDE THE * PREPARE RECORDS WHICH WERE STARTED IN A PREVIOUS MBYTE. * ------------------------------------------------------------------- */ tlastPrepRef = logFilePtr.p->logLastPrepRef[tmbyte]; logPartPtr.p->startMbyte = tlastPrepRef & 65535; LogFileRecordPtr locLogFilePtr; findLogfile(signal, tlastPrepRef >> 16, logPartPtr, &locLogFilePtr); logPartPtr.p->startLogfile = locLogFilePtr.i; logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; }//if }//if if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG) { if (tmbyte == 0) { jam(); tmbyte = ZNO_MBYTES_IN_FILE - 1; logFilePtr.i = logFilePtr.p->prevLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); } else { jam(); tmbyte--; }//if if (logPartPtr.p->lastLogfile == logFilePtr.i) { ndbrequire(logPartPtr.p->lastMbyte != tmbyte); }//if if (loopCount > 20) { jam(); signal->theData[0] = ZSR_LOG_LIMITS; signal->theData[1] = logPartPtr.i; signal->theData[2] = logFilePtr.i; signal->theData[3] = tmbyte; sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); return; }//if loopCount++; } else { jam(); break; }//if }//while /* ------------------------------------------------------------------------ * WE HAVE NOW FOUND BOTH THE START AND THE STOP OF THE LOG. NOW START * EXECUTING THE LOG. THE FIRST ACTION IS TO OPEN THE LOG FILE WHERE TO * START EXECUTING THE LOG. * ----------------------------------------------------------------------- */ if (logPartPtr.p->logPartState == LogPartRecord::SR_THIRD_PHASE_STARTED) { jam(); logFilePtr.i = logPartPtr.p->startLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_START; openFileRw(signal, logFilePtr); } else { jam(); ndbrequire(logPartPtr.p->logPartState == LogPartRecord::SR_FOURTH_PHASE_STARTED); /* -------------------------------------------------------------------- * WE HAVE NOW FOUND THE TAIL MBYTE IN THE TAIL FILE. * SET THOSE PARAMETERS IN THE LOG PART. * WE HAVE ALSO FOUND THE HEAD MBYTE. WE STILL HAVE TO SEARCH * FOR THE PAGE NUMBER AND PAGE INDEX WHERE TO SET THE HEAD. * ------------------------------------------------------------------- */ logFilePtr.i = logPartPtr.p->startLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.p->logTailFileNo = logFilePtr.p->fileNo; logPartPtr.p->logTailMbyte = logPartPtr.p->startMbyte; /* -------------------------------------------------------------------- * THE HEAD WE ACTUALLY FOUND DURING EXECUTION OF LOG SO WE USE * THIS INFO HERE RATHER THAN THE MBYTE WE FOUND TO BE THE HEADER. * ------------------------------------------------------------------- */ LogFileRecordPtr locLogFilePtr; findLogfile(signal, logPartPtr.p->headFileNo, logPartPtr, &locLogFilePtr); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE; openFileRw(signal, locLogFilePtr); }//if return; }//Dblqh::srLogLimits() void Dblqh::openExecSrStartLab(Signal* signal) { logPartPtr.p->currentLogfile = logFilePtr.i; logFilePtr.p->currentMbyte = logPartPtr.p->startMbyte; /* ------------------------------------------------------------------------ * WE NEED A TC CONNECT RECORD TO HANDLE EXECUTION OF LOG RECORDS. * ------------------------------------------------------------------------ */ seizeTcrec(); logPartPtr.p->logTcConrec = tcConnectptr.i; /* ------------------------------------------------------------------------ * THE FIRST LOG RECORD TO EXECUTE IS ALWAYS AT A NEW MBYTE. * SET THE NUMBER OF PAGES IN THE MAIN MEMORY BUFFER TO ZERO AS AN INITIAL * VALUE. THIS VALUE WILL BE UPDATED AND ENSURED THAT IT RELEASES PAGES IN * THE SUBROUTINE READ_EXEC_SR. * ----------------------------------------------------------------------- */ logPartPtr.p->mmBufferSize = 0; readExecSrNewMbyte(signal); return; }//Dblqh::openExecSrStartLab() /* --------------------------------------------------------------------------- * WE WILL ALWAYS ENSURE THAT WE HAVE AT LEAST 16 KBYTE OF LOG PAGES WHEN WE * START READING A LOG RECORD. THE ONLY EXCEPTION IS WHEN WE COME CLOSE TO A * MBYTE BOUNDARY. SINCE WE KNOW THAT LOG RECORDS ARE NEVER WRITTEN ACROSS A * MBYTE BOUNDARY THIS IS NOT A PROBLEM. * * WE START BY READING 64 KBYTE BEFORE STARTING TO EXECUTE THE LOG RECORDS. * WHEN WE COME BELOW 64 KBYTE WE READ ANOTHER SET OF LOG PAGES. WHEN WE * GO BELOW 16 KBYTE WE WAIT UNTIL THE READ PAGES HAVE ENTERED THE BLOCK. * ------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- * NEW PAGES FROM LOG FILE DURING EXECUTION OF LOG HAS ARRIVED. * ------------------------------------------------------------------------- */ void Dblqh::readExecSrLab(Signal* signal) { buildLinkedLogPageList(signal); /* ------------------------------------------------------------------------ * WE NEED TO SET THE CURRENT PAGE INDEX OF THE FIRST PAGE SINCE IT CAN BE * USED IMMEDIATELY WITHOUT ANY OTHER INITIALISATION. THE REST OF THE PAGES * WILL BE INITIALISED BY READ_LOGWORD. * ----------------------------------------------------------------------- */ logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; if (logPartPtr.p->logExecState == LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE) { jam(); /* ---------------------------------------------------------------------- * THIS IS THE FIRST READ DURING THE EXECUTION OF THIS MBYTE. SET THE * NEW CURRENT LOG PAGE TO THE FIRST OF THESE PAGES. CHANGE * LOG_EXEC_STATE TO ENSURE THAT WE START EXECUTION OF THE LOG. * --------------------------------------------------------------------- */ logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE; logPartPtr.p->prevFilepage = logFilePtr.p->currentFilepage; logFilePtr.p->currentLogpage = lfoPtr.p->firstLfoPage; logPartPtr.p->prevLogpage = logFilePtr.p->currentLogpage; }//if moveToPageRef(signal); releaseLfo(signal); /* ------------------------------------------------------------------------ * NOW WE HAVE COMPLETED THE RECEPTION OF THESE PAGES. * NOW CHECK IF WE NEED TO READ MORE PAGES. * ----------------------------------------------------------------------- */ checkReadExecSr(signal); if (logPartPtr.p->logExecState == LogPartRecord::LES_EXEC_LOG) { jam(); signal->theData[0] = ZEXEC_SR; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//if return; }//Dblqh::readExecSrLab() void Dblqh::openExecSrNewMbyteLab(Signal* signal) { readExecSrNewMbyte(signal); return; }//Dblqh::openExecSrNewMbyteLab() void Dblqh::closeExecSrLab(Signal* signal) { LogFileRecordPtr locLogFilePtr; logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); locLogFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE; openFileRw(signal, locLogFilePtr); return; }//Dblqh::closeExecSrLab() void Dblqh::writeDirtyLab(Signal* signal) { releaseLfo(signal); signal->theData[0] = logPartPtr.i; execSr(signal); return; }//Dblqh::writeDirtyLab() /* -------------------------------------------------------------------------- * EXECUTE A LOG RECORD WITHIN THE CURRENT MBYTE. * ------------------------------------------------------------------------- */ void Dblqh::execSr(Signal* signal) { LogFileRecordPtr nextLogFilePtr; LogPageRecordPtr tmpLogPagePtr; Uint32 logWord; jamEntry(); logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); do { jam(); logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logPartPtr.p->prevLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); if (logPagePtr.p->logPageWord[ZPOS_DIRTY] == ZDIRTY) { jam(); switch (logPartPtr.p->logExecState) { case LogPartRecord::LES_EXEC_LOG_COMPLETED: case LogPartRecord::LES_EXEC_LOG_NEW_FILE: case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE: jam(); /* ------------------------------------------------------------------ * IN THIS WE HAVE COMPLETED EXECUTION OF THE CURRENT LOG PAGE * AND CAN WRITE IT TO DISK SINCE IT IS DIRTY. * ----------------------------------------------------------------- */ writeDirty(signal); return; break; case LogPartRecord::LES_EXEC_LOG: jam(); /* -------------------------------------------------------------------- * IN THIS CASE WE ONLY WRITE THE PAGE TO DISK IF WE HAVE COMPLETED * EXECUTION OF LOG RECORDS BELONGING TO THIS LOG PAGE. * ------------------------------------------------------------------- */ if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { jam(); writeDirty(signal); return; }//if break; default: ndbrequire(false); break; }//switch }//if if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { jam(); logPartPtr.p->prevLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logPartPtr.p->prevFilepage++; continue; }//if switch (logPartPtr.p->logExecState) { case LogPartRecord::LES_EXEC_LOG_COMPLETED: jam(); releaseMmPages(signal); logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR_COMPLETED; closeFile(signal, logFilePtr); return; break; case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE: jam(); logFilePtr.p->currentMbyte++; readExecSrNewMbyte(signal); return; break; case LogPartRecord::LES_EXEC_LOG_NEW_FILE: jam(); nextLogFilePtr.i = logFilePtr.p->nextLogFile; logPartPtr.p->currentLogfile = nextLogFilePtr.i; ptrCheckGuard(nextLogFilePtr, clogFileFileSize, logFileRecord); nextLogFilePtr.p->currentMbyte = 0; logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR; closeFile(signal, logFilePtr); return; break; case LogPartRecord::LES_EXEC_LOG: jam(); /*empty*/; break; default: jam(); systemErrorLab(signal); return; break; }//switch logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPartPtr.p->savePageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; if (logPartPtr.p->execSrPagesRead < ZMIN_READ_BUFFER_SIZE) { /* -------------------------------------------------------------------- * THERE WERE LESS THAN 16 KBYTE OF LOG PAGES REMAINING. WE WAIT UNTIL * THE NEXT 64 KBYTE ARRIVES UNTIL WE CONTINUE AGAIN. * ------------------------------------------------------------------- */ if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesExecuted) < ZPAGES_IN_MBYTE) { jam(); /* ------------------------------------------------------------------ * WE ONLY STOP AND WAIT IF THERE MORE PAGES TO READ. IF IT IS NOT * THEN IT IS THE END OF THE MBYTE AND WE WILL CONTINUE. IT IS NO * RISK THAT A LOG RECORD WE FIND WILL NOT BE READ AT THIS TIME * SINCE THE LOG RECORDS NEVER SPAN OVER A MBYTE BOUNDARY. * ----------------------------------------------------------------- */ readExecSr(signal); logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR; return; }//if }//if logWord = readLogword(signal); switch (logWord) { /* ========================================================================= */ /* ========================================================================= */ case ZPREP_OP_TYPE: { logWord = readLogword(signal); stepAhead(signal, logWord - 2); break; } /* ========================================================================= */ /* ========================================================================= */ case ZINVALID_COMMIT_TYPE: jam(); stepAhead(signal, ZCOMMIT_LOG_SIZE - 1); break; /* ========================================================================= */ /* ========================================================================= */ case ZCOMMIT_TYPE: { CommitLogRecord commitLogRecord; jam(); tcConnectptr.i = logPartPtr.p->logTcConrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); readCommitLog(signal, &commitLogRecord); if (tcConnectptr.p->gci > crestartNewestGci) { jam(); /*---------------------------------------------------------------------------*/ /* THIS LOG RECORD MUST BE IGNORED. IT IS PART OF A GLOBAL CHECKPOINT WHICH */ /* WILL BE INVALIDATED BY THE SYSTEM RESTART. IF NOT INVALIDATED IT MIGHT BE */ /* EXECUTED IN A FUTURE SYSTEM RESTART. */ /*---------------------------------------------------------------------------*/ tmpLogPagePtr.i = logPartPtr.p->prevLogpage; ptrCheckGuard(tmpLogPagePtr, clogPageFileSize, logPageRecord); arrGuard(logPartPtr.p->savePageIndex, ZPAGE_SIZE); tmpLogPagePtr.p->logPageWord[logPartPtr.p->savePageIndex] = ZINVALID_COMMIT_TYPE; tmpLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZDIRTY; } else { jam(); /*---------------------------------------------------------------------------*/ /* CHECK IF I AM SUPPOSED TO EXECUTE THIS LOG RECORD. IF I AM THEN SAVE PAGE */ /* INDEX IN CURRENT LOG PAGE SINCE IT WILL BE OVERWRITTEN WHEN EXECUTING THE */ /* LOG RECORD. */ /*---------------------------------------------------------------------------*/ logPartPtr.p->execSrExecuteIndex = 0; Uint32 result = checkIfExecLog(signal); if (result == ZOK) { jam(); //*---------------------------------------------------------------------------*/ /* IN A NODE RESTART WE WILL NEVER END UP HERE SINCE NO FRAGMENTS HAVE BEEN */ /* DEFINED YET. THUS NO EXTRA CHECKING FOR NODE RESTART IS NECESSARY. */ /*---------------------------------------------------------------------------*/ logPartPtr.p->savePageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; tcConnectptr.p->fragmentptr = fragptr.i; findPageRef(signal, &commitLogRecord); logPartPtr.p->execSrLogPageIndex = commitLogRecord.startPageIndex; if (logPagePtr.i != RNIL) { jam(); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = commitLogRecord.startPageIndex; logPartPtr.p->execSrLogPage = logPagePtr.i; execLogRecord(signal); return; }//if logPartPtr.p->execSrStartPageNo = commitLogRecord.startPageNo; logPartPtr.p->execSrStopPageNo = commitLogRecord.stopPageNo; findLogfile(signal, commitLogRecord.fileNo, logPartPtr, &logFilePtr); logPartPtr.p->execSrExecLogFile = logFilePtr.i; if (logFilePtr.i == logPartPtr.p->currentLogfile) { jam(); readExecLog(signal); lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG; return; } else { jam(); /*---------------------------------------------------------------------------*/ /* THE FILE IS CURRENTLY NOT OPEN. WE MUST OPEN IT BEFORE WE CAN READ FROM */ /* THE FILE. */ /*---------------------------------------------------------------------------*/ logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_LOG; openFileRw(signal, logFilePtr); return; }//if }//if }//if break; } /* ========================================================================= */ /* ========================================================================= */ case ZABORT_TYPE: jam(); stepAhead(signal, ZABORT_LOG_SIZE - 1); break; /* ========================================================================= */ /* ========================================================================= */ case ZFD_TYPE: jam(); /*---------------------------------------------------------------------------*/ /* THIS IS THE FIRST ITEM WE ENCOUNTER IN A NEW FILE. AT THIS MOMENT WE SHALL*/ /* SIMPLY BYPASS IT. IT HAS NO SIGNIFANCE WHEN EXECUTING THE LOG. IT HAS ITS */ /* SIGNIFANCE WHEN FINDING THE START END THE END OF THE LOG. */ /* WE HARDCODE THE PAGE INDEX SINCE THIS SHOULD NEVER BE FOUND AT ANY OTHER */ /* PLACE THAN IN THE FIRST PAGE OF A NEW FILE IN THE FIRST POSITION AFTER THE*/ /* HEADER. */ /*---------------------------------------------------------------------------*/ ndbrequire(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == (ZPAGE_HEADER_SIZE + ZPOS_NO_FD)); { Uint32 noFdDescriptors = logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD]; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = (ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (noFdDescriptors * ZFD_PART_SIZE); } break; /* ========================================================================= */ /* ========================================================================= */ case ZNEXT_LOG_RECORD_TYPE: jam(); stepAhead(signal, ZPAGE_SIZE - logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]); break; /* ========================================================================= */ /* ========================================================================= */ case ZNEXT_MBYTE_TYPE: /*---------------------------------------------------------------------------*/ /* WE WILL SKIP A PART OF THE LOG FILE. ACTUALLY THE NEXT POINTER IS TO */ /* A NEW MBYTE. THEREFORE WE WILL START UP A NEW MBYTE. THIS NEW MBYTE IS */ /* HOWEVER ONLY STARTED IF IT IS NOT AFTER THE STOP MBYTE. */ /* IF WE HAVE REACHED THE END OF THE STOP MBYTE THEN THE EXECUTION OF THE LOG*/ /* IS COMPLETED. */ /*---------------------------------------------------------------------------*/ if (logPartPtr.p->currentLogfile == logPartPtr.p->stopLogfile) { if (logFilePtr.p->currentMbyte == logPartPtr.p->stopMbyte) { jam(); /*---------------------------------------------------------------------------*/ /* THIS WAS THE LAST MBYTE TO EXECUTE IN THIS LOG PART. WE SHOULD HAVE FOUND */ /* A COMPLETED GCI RECORD OF THE LAST GCI BEFORE THIS. FOR SOME REASON THIS */ /* RECORD WAS NOT AVAILABLE ON THE LOG. CRASH THE SYSTEM, A VERY SERIOUS */ /* ERROR WHICH WE MUST REALLY WORK HARD TO AVOID. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM. */ /*---------------------------------------------------------------------------*/ signal->theData[0] = RNIL; signal->theData[1] = logPartPtr.i; Uint32 tmp = logFilePtr.p->fileName[3]; tmp = (tmp >> 8) & 0xff;// To get the Directory, DXX. signal->theData[2] = tmp; signal->theData[3] = logFilePtr.p->fileNo; signal->theData[4] = logFilePtr.p->currentFilepage; signal->theData[5] = logFilePtr.p->currentMbyte; signal->theData[6] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; sendSignal(cownref, GSN_DEBUG_SIG, signal, 7, JBA); return; }//if }//if /*---------------------------------------------------------------------------*/ /* START EXECUTION OF A NEW MBYTE IN THE LOG. */ /*---------------------------------------------------------------------------*/ if (logFilePtr.p->currentMbyte < (ZNO_MBYTES_IN_FILE - 1)) { jam(); logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_MBYTE; } else { ndbrequire(logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)); jam(); /*---------------------------------------------------------------------------*/ /* WE HAVE TO CHANGE FILE. CLOSE THIS ONE AND THEN OPEN THE NEXT. */ /*---------------------------------------------------------------------------*/ logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_FILE; }//if break; /* ========================================================================= */ /* ========================================================================= */ case ZCOMPLETED_GCI_TYPE: jam(); logWord = readLogword(signal); if (logWord == logPartPtr.p->logLastGci) { jam(); /*---------------------------------------------------------------------------*/ /* IF IT IS THE LAST GCI TO LIVE AFTER SYSTEM RESTART THEN WE RECORD THE NEXT*/ /* WORD AS THE NEW HEADER OF THE LOG FILE. OTHERWISE WE SIMPLY IGNORE THIS */ /* LOG RECORD. */ /*---------------------------------------------------------------------------*/ if (csrPhasesCompleted == 0) { jam(); /*---------------------------------------------------------------------------*/ /*WE ONLY RECORD THE HEAD OF THE LOG IN THE FIRST LOG ROUND OF LOG EXECUTION.*/ /*---------------------------------------------------------------------------*/ logPartPtr.p->headFileNo = logFilePtr.p->fileNo; logPartPtr.p->headPageNo = logFilePtr.p->currentFilepage; logPartPtr.p->headPageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; }//if /*---------------------------------------------------------------------------*/ /* THERE IS NO NEED OF EXECUTING PAST THIS LINE SINCE THERE WILL ONLY BE LOG */ /* RECORDS THAT WILL BE OF NO INTEREST. THUS CLOSE THE FILE AND START THE */ /* NEXT PHASE OF THE SYSTEM RESTART. */ /*---------------------------------------------------------------------------*/ logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_COMPLETED; }//if break; default: jam(); /* ========================================================================= */ /* ========================================================================= */ /*---------------------------------------------------------------------------*/ /* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM. */ /*---------------------------------------------------------------------------*/ signal->theData[0] = RNIL; signal->theData[1] = logPartPtr.i; Uint32 tmp = logFilePtr.p->fileName[3]; tmp = (tmp >> 8) & 0xff;// To get the Directory, DXX. signal->theData[2] = tmp; signal->theData[3] = logFilePtr.p->fileNo; signal->theData[4] = logFilePtr.p->currentMbyte; signal->theData[5] = logFilePtr.p->currentFilepage; signal->theData[6] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; signal->theData[7] = logWord; sendSignal(cownref, GSN_DEBUG_SIG, signal, 8, JBA); return; break; }//switch /*---------------------------------------------------------------------------*/ // We continue to execute log records until we find a proper one to execute or // that we reach a new page. /*---------------------------------------------------------------------------*/ } while (1); }//Dblqh::execSr() /*---------------------------------------------------------------------------*/ /* THIS SIGNAL IS ONLY RECEIVED TO BE CAPTURED IN THE SIGNAL LOG. IT IS */ /* ALSO USED TO CRASH THE SYSTEM AFTER SENDING A SIGNAL TO THE LOG. */ /*---------------------------------------------------------------------------*/ void Dblqh::execDEBUG_SIG(Signal* signal) { /* 2.5 TEMPORARY VARIABLES ----------------------- */ UintR tdebug; jamEntry(); logPagePtr.i = signal->theData[0]; tdebug = logPagePtr.p->logPageWord[0]; char buf[100]; snprintf(buf, 100, "Error while reading REDO log.\n" "D=%d, F=%d Mb=%d FP=%d W1=%d W2=%d", signal->theData[2], signal->theData[3], signal->theData[4], signal->theData[5], signal->theData[6], signal->theData[7]); progError(__LINE__, ERR_SR_REDOLOG, buf); return; }//Dblqh::execDEBUG_SIG() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ void Dblqh::closeExecLogLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; signal->theData[0] = ZEXEC_SR; signal->theData[1] = logFilePtr.p->logPartRec; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//Dblqh::closeExecLogLab() void Dblqh::openExecLogLab(Signal* signal) { readExecLog(signal); lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG; return; }//Dblqh::openExecLogLab() void Dblqh::readExecLogLab(Signal* signal) { buildLinkedLogPageList(signal); logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOGREC_FROM_FILE; logPartPtr.p->execSrLfoRec = lfoPtr.i; logPartPtr.p->execSrLogPage = logPagePtr.i; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->execSrLogPageIndex; execLogRecord(signal); return; }//Dblqh::readExecLogLab() /*---------------------------------------------------------------------------*/ /* THIS CODE IS USED TO EXECUTE A LOG RECORD WHEN IT'S DATA HAVE BEEN LOCATED*/ /* AND TRANSFERRED INTO MEMORY. */ /*---------------------------------------------------------------------------*/ void Dblqh::execLogRecord(Signal* signal) { jamEntry(); tcConnectptr.i = logPartPtr.p->logTcConrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); // Read a log record and prepare it for execution readLogHeader(signal); readKey(signal); readAttrinfo(signal); initReqinfoExecSr(signal); arrGuard(logPartPtr.p->execSrExecuteIndex, 4); BlockReference ref = fragptr.p->execSrBlockref[logPartPtr.p->execSrExecuteIndex]; tcConnectptr.p->nextReplica = refToNode(ref); tcConnectptr.p->connectState = TcConnectionrec::LOG_CONNECTED; tcConnectptr.p->tcOprec = tcConnectptr.i; packLqhkeyreqLab(signal); return; }//Dblqh::execLogRecord() //---------------------------------------------------------------------------- // This function invalidates log pages after the last GCI record in a // system/node restart. This is to ensure that the end of the log is // consistent. This function is executed last in start phase 3. // RT 450. EDTJAMO. //---------------------------------------------------------------------------- void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { jam(); if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG_INVALIDATE) { jam(); systemError(signal); } if (logFilePtr.p->fileNo != logPartPtr.p->invalidateFileNo) { jam(); systemError(signal); } switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); releaseLfo(signal); releaseLogpage(signal); if (logPartPtr.p->invalidatePageNo < (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE - 1)) { // We continue in this file. logPartPtr.p->invalidatePageNo++; } else { // We continue in the next file. logFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo; // Page 0 is used for file descriptors. logPartPtr.p->invalidatePageNo = 1; if (logFilePtr.p->logFileStatus != LogFileRecord::OPEN) { jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_INVALIDATE_PAGES; openFileRw(signal, logFilePtr); return; break; } } // Read a page from the log file. readFileInInvalidate(signal); return; break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam(); releaseLfo(signal); // Check if this page must be invalidated. // If the log lap number on a page after the head of the tail is the same // as the actual log lap number we must invalidate this page. Otherwise it // could be impossible to find the end of the log in a later system/node // restart. if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] == logPartPtr.p->logLap) { // This page must be invalidated. logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 0; // Contact NDBFS. Real time break. writeSinglePage(signal, logPartPtr.p->invalidatePageNo, ZPAGE_SIZE - 1); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; } else { // We are done with invalidating. Finish start phase 3.4. exitFromInvalidate(signal); } return; break; default: jam(); systemError(signal); return; break; } return; }//Dblqh::invalidateLogAfterLastGCI void Dblqh::readFileInInvalidate(Signal* signal) { jam(); // Contact NDBFS. Real time break. readSinglePage(signal, logPartPtr.p->invalidatePageNo); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_INVALIDATE_PAGES; } void Dblqh::exitFromInvalidate(Signal* signal) { jam(); // Close files if necessary. Current file and the next file should be // left open. if (logFilePtr.i != logPartPtr.p->currentLogfile) { LogFileRecordPtr currentLogFilePtr; LogFileRecordPtr nextAfterCurrentLogFilePtr; currentLogFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(currentLogFilePtr, clogFileFileSize, logFileRecord); nextAfterCurrentLogFilePtr.i = currentLogFilePtr.p->nextLogFile; if (logFilePtr.i != nextAfterCurrentLogFilePtr.i) { // This file should be closed. logFilePtr.p->logFileStatus = LogFileRecord::CLOSE_SR_INVALIDATE_PAGES; closeFile(signal, logFilePtr); // Return from this function and wait for close confirm. Then come back // and test the previous file for closing. return; } } // We are done with closing files, send completed signal and exit this phase. signal->theData[0] = ZSR_FOURTH_COMP; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; } /*---------------------------------------------------------------------------*/ /* THE EXECUTION OF A LOG RECORD IS COMPLETED. RELEASE PAGES IF THEY WERE */ /* READ FROM DISK FOR THIS PARTICULAR OPERATION. */ /*---------------------------------------------------------------------------*/ void Dblqh::completedLab(Signal* signal) { Uint32 result = returnExecLog(signal); /*---------------------------------------------------------------------------*/ /* ENTER COMPLETED WITH */ /* LQH_CONNECTPTR */ /*---------------------------------------------------------------------------*/ if (result == ZOK) { jam(); execLogRecord(signal); return; } else if (result == ZNOT_OK) { jam(); signal->theData[0] = ZEXEC_SR; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); } else { jam(); /*empty*/; }//if /*---------------------------------------------------------------------------*/ /* WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE PROCEEDING IN */ /* RARE CASES. */ /*---------------------------------------------------------------------------*/ return; }//Dblqh::completedLab() /*---------------------------------------------------------------------------*/ /* EXECUTION OF LOG RECORD WAS NOT SUCCESSFUL. CHECK IF IT IS OK ANYWAY, */ /* THEN EXECUTE THE NEXT LOG RECORD. */ /*---------------------------------------------------------------------------*/ void Dblqh::logLqhkeyrefLab(Signal* signal) { Uint32 result = returnExecLog(signal); switch (tcConnectptr.p->operation) { case ZUPDATE: case ZDELETE: jam(); ndbrequire(terrorCode == ZNO_TUPLE_FOUND); break; case ZINSERT: jam(); ndbrequire(terrorCode == ZTUPLE_ALREADY_EXIST); break; default: ndbrequire(false); return; break; }//switch if (result == ZOK) { jam(); execLogRecord(signal); return; } else if (result == ZNOT_OK) { jam(); signal->theData[0] = ZEXEC_SR; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); } else { jam(); /*empty*/; }//if /* ------------------------------------------------------------------------ * WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE * PROCEEDING IN RARE CASES. * ----------------------------------------------------------------------- */ return; }//Dblqh::logLqhkeyrefLab() void Dblqh::closeExecSrCompletedLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; signal->theData[0] = logFilePtr.p->logPartRec; execLogComp(signal); return; }//Dblqh::closeExecSrCompletedLab() /* -------------------------------------------------------------------------- * ONE OF THE LOG PARTS HAVE COMPLETED EXECUTING THE LOG. CHECK IF ALL LOG * PARTS ARE COMPLETED. IF SO START SENDING EXEC_FRAGCONF AND EXEC_SRCONF. * ------------------------------------------------------------------------- */ void Dblqh::execLogComp(Signal* signal) { logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_COMPLETED; /* ------------------------------------------------------------------------ * WE MUST RELEASE THE TC CONNECT RECORD HERE SO THAT IT CAN BE REUSED. * ----------------------------------------------------------------------- */ tcConnectptr.i = logPartPtr.p->logTcConrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); releaseTcrecLog(signal, tcConnectptr); for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_COMPLETED) { if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_STARTED) { jam(); systemErrorLab(signal); return; } else { jam(); /* ------------------------------------------------------------------ * THIS LOG PART WAS NOT COMPLETED YET. EXIT AND WAIT FOR IT * TO COMPLETE * ----------------------------------------------------------------- */ return; }//if }//if }//for /* ------------------------------------------------------------------------ * ALL LOG PARTS HAVE COMPLETED THE EXECUTION OF THE LOG. WE CAN NOW START * SENDING THE EXEC_FRAGCONF SIGNALS TO ALL INVOLVED FRAGMENTS. * ----------------------------------------------------------------------- */ if (cstartType != NodeState::ST_NODE_RESTART) { jam(); signal->theData[0] = ZSEND_EXEC_CONF; signal->theData[1] = 0; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); } else { jam(); /* ---------------------------------------------------------------------- * FOR NODE RESTART WE CAN SKIP A NUMBER OF STEPS SINCE WE HAVE NO * FRAGMENTS DEFINED AT THIS POINT. OBVIOUSLY WE WILL NOT NEED TO * EXECUTE ANY MORE LOG STEPS EITHER AND THUS WE CAN IMMEDIATELY * START FINDING THE END AND THE START OF THE LOG. * --------------------------------------------------------------------- */ csrPhasesCompleted = 3; execSrCompletedLab(signal); return; }//if return; }//Dblqh::execLogComp() /* -------------------------------------------------------------------------- * GO THROUGH THE FRAGMENT RECORDS TO DEDUCE TO WHICH SHALL BE SENT * EXEC_FRAGCONF AFTER COMPLETING THE EXECUTION OF THE LOG. * ------------------------------------------------------------------------- */ void Dblqh::sendExecConf(Signal* signal) { jamEntry(); fragptr.i = signal->theData[0]; Uint32 loopCount = 0; while (fragptr.i < cfragrecFileSize) { ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); if (fragptr.p->execSrStatus != Fragrecord::IDLE) { jam(); ndbrequire(fragptr.p->execSrNoReplicas - 1 < 4); for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) { jam(); signal->theData[0] = fragptr.p->execSrUserptr[i]; sendSignal(fragptr.p->execSrBlockref[i], GSN_EXEC_FRAGCONF, signal, 1, JBB); }//for if (fragptr.p->execSrStatus == Fragrecord::ACTIVE) { jam(); fragptr.p->execSrStatus = Fragrecord::IDLE; } else { ndbrequire(fragptr.p->execSrStatus == Fragrecord::ACTIVE_REMOVE_AFTER); jam(); Uint32 fragId = fragptr.p->fragId; tabptr.i = fragptr.p->tabRef; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); deleteFragrec(fragId); }//if fragptr.p->execSrNoReplicas = 0; }//if loopCount++; if (loopCount > 20) { jam(); signal->theData[0] = ZSEND_EXEC_CONF; signal->theData[1] = fragptr.i + 1; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; } else { jam(); fragptr.i++; }//if }//while /* ---------------------------------------------------------------------- * WE HAVE NOW SENT ALL EXEC_FRAGCONF. NOW IT IS TIME TO SEND * EXEC_SRCONF TO ALL NODES. * --------------------------------------------------------------------- */ srPhase3Comp(signal); }//Dblqh::sendExecConf() /* -------------------------------------------------------------------------- * PHASE 3 HAS NOW COMPLETED. INFORM ALL OTHER NODES OF THIS EVENT. * ------------------------------------------------------------------------- */ void Dblqh::srPhase3Comp(Signal* signal) { jamEntry(); ndbrequire(cnoOfNodes < MAX_NDB_NODES); for (Uint32 i = 0; i < cnoOfNodes; i++) { jam(); if (cnodeStatus[i] == ZNODE_UP) { jam(); ndbrequire(cnodeData[i] < MAX_NDB_NODES); BlockReference ref = calcLqhBlockRef(cnodeData[i]); signal->theData[0] = cownNodeid; sendSignal(ref, GSN_EXEC_SRCONF, signal, 1, JBB); }//if }//for return; }//Dblqh::srPhase3Comp() /* ########################################################################## * SYSTEM RESTART PHASE FOUR MODULE * THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. * * THIS MODULE SETS UP THE HEAD AND TAIL POINTERS OF THE LOG PARTS IN THE * FRAGMENT LOG. WHEN IT IS COMPLETED IT REPORTS TO THE MASTER DIH THAT * IT HAS COMPLETED THE PART OF THE SYSTEM RESTART WHERE THE DATABASE IS * LOADED. * IT ALSO OPENS THE CURRENT LOG FILE AND THE NEXT AND SETS UP THE FIRST * LOG PAGE WHERE NEW LOG DATA IS TO BE INSERTED WHEN THE SYSTEM STARTS * AGAIN. * * THIS PART IS ACTUALLY EXECUTED FOR ALL RESTART TYPES. * ######################################################################### */ void Dblqh::initFourth(Signal* signal) { LogFileRecordPtr locLogFilePtr; jamEntry(); logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); crestartNewestGci = 1; crestartOldestGci = 1; /* ------------------------------------------------------------------------ * INITIALISE LOG PART AND LOG FILES AS NEEDED. * ----------------------------------------------------------------------- */ logPartPtr.p->headFileNo = 0; logPartPtr.p->headPageNo = 1; logPartPtr.p->headPageIndex = ZPAGE_HEADER_SIZE + 2; logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED; logPartPtr.p->logTailFileNo = 0; logPartPtr.p->logTailMbyte = 0; locLogFilePtr.i = logPartPtr.p->firstLogfile; ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE; openFileRw(signal, locLogFilePtr); return; }//Dblqh::initFourth() void Dblqh::openSrFourthPhaseLab(Signal* signal) { /* ------------------------------------------------------------------------ * WE HAVE NOW OPENED THE HEAD LOG FILE WE WILL NOW START READING IT * FROM THE HEAD MBYTE TO FIND THE NEW HEAD OF THE LOG. * ----------------------------------------------------------------------- */ readSinglePage(signal, logPartPtr.p->headPageNo); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_PHASE; return; }//Dblqh::openSrFourthPhaseLab() void Dblqh::readSrFourthPhaseLab(Signal* signal) { if(c_diskless){ jam(); logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; } /* ------------------------------------------------------------------------ * INITIALISE ALL LOG PART INFO AND LOG FILE INFO THAT IS NEEDED TO * START UP THE SYSTEM. * ------------------------------------------------------------------------ * INITIALISE THE NEWEST GLOBAL CHECKPOINT IDENTITY AND THE NEWEST * COMPLETED GLOBAL CHECKPOINT IDENITY AS THE NEWEST THAT WAS RESTARTED. * ------------------------------------------------------------------------ * INITIALISE THE HEAD PAGE INDEX IN THIS PAGE. * ASSIGN IT AS THE CURRENT LOGPAGE. * ASSIGN THE FILE AS THE CURRENT LOG FILE. * ASSIGN THE CURRENT FILE NUMBER FROM THE CURRENT LOG FILE AND THE NEXT * FILE NUMBER FROM THE NEXT LOG FILE. * ASSIGN THE CURRENT FILEPAGE FROM HEAD PAGE NUMBER. * ASSIGN THE CURRENT MBYTE BY DIVIDING PAGE NUMBER BY 128. * INITIALISE LOG LAP TO BE THE LOG LAP AS FOUND IN THE HEAD PAGE. * WE HAVE TO CALCULATE THE NUMBER OF REMAINING WORDS IN THIS MBYTE. * ----------------------------------------------------------------------- */ cnewestGci = crestartNewestGci; cnewestCompletedGci = crestartNewestGci; logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; logPartPtr.p->currentLogfile = logFilePtr.i; logFilePtr.p->filePosition = logPartPtr.p->headPageNo; logFilePtr.p->currentMbyte = logPartPtr.p->headPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE; logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP]; logFilePtr.p->currentFilepage = logPartPtr.p->headPageNo; logFilePtr.p->currentLogpage = logPagePtr.i; initLogpage(signal); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->headPageIndex; logFilePtr.p->remainingWordsInMbyte = (( ((logFilePtr.p->currentMbyte + 1) * ZPAGES_IN_MBYTE) - logFilePtr.p->currentFilepage) * (ZPAGE_SIZE - ZPAGE_HEADER_SIZE)) - (logPartPtr.p->headPageIndex - ZPAGE_HEADER_SIZE); /* ------------------------------------------------------------------------ * THE NEXT STEP IS TO OPEN THE NEXT LOG FILE (IF THERE IS ONE). * ----------------------------------------------------------------------- */ if (logFilePtr.p->nextLogFile != logFilePtr.i) { LogFileRecordPtr locLogFilePtr; jam(); locLogFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_NEXT; openFileRw(signal, locLogFilePtr); } else { jam(); /* ---------------------------------------------------------------------- * THIS CAN ONLY OCCUR IF WE HAVE ONLY ONE LOG FILE. THIS LOG FILE MUST * BE LOG FILE ZERO AND THAT IS THE FILE WE CURRENTLY HAVE READ. * THUS WE CAN CONTINUE IMMEDIATELY TO READ PAGE ZERO IN FILE ZERO. * --------------------------------------------------------------------- */ openSrFourthZeroSkipInitLab(signal); return; }//if return; }//Dblqh::readSrFourthPhaseLab() void Dblqh::openSrFourthNextLab(Signal* signal) { /* ------------------------------------------------------------------------ * WE MUST ALSO HAVE FILE 0 OPEN ALL THE TIME. * ----------------------------------------------------------------------- */ logFilePtr.i = logPartPtr.p->firstLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); if (logFilePtr.p->logFileStatus == LogFileRecord::OPEN) { jam(); openSrFourthZeroSkipInitLab(signal); return; } else { jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_ZERO; openFileRw(signal, logFilePtr); }//if return; }//Dblqh::openSrFourthNextLab() void Dblqh::openSrFourthZeroLab(Signal* signal) { openSrFourthZeroSkipInitLab(signal); return; }//Dblqh::openSrFourthZeroLab() void Dblqh::openSrFourthZeroSkipInitLab(Signal* signal) { if (logFilePtr.i == logPartPtr.p->currentLogfile) { if (logFilePtr.p->currentFilepage == 0) { jam(); /* ------------------------------------------------------------------- * THE HEADER PAGE IN THE LOG IS PAGE ZERO IN FILE ZERO. * THIS SHOULD NEVER OCCUR. * ------------------------------------------------------------------- */ systemErrorLab(signal); return; }//if }//if readSinglePage(signal, 0); lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_ZERO; return; }//Dblqh::openSrFourthZeroSkipInitLab() void Dblqh::readSrFourthZeroLab(Signal* signal) { logFilePtr.p->logPageZero = logPagePtr.i; // -------------------------------------------------------------------- // This is moved to invalidateLogAfterLastGCI(), RT453. // signal->theData[0] = ZSR_FOURTH_COMP; // signal->theData[1] = logPartPtr.i; // sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); // -------------------------------------------------------------------- // Need to invalidate log pages after the head of the log. RT 453. EDTJAMO. // Set the start of the invalidation. logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.p->invalidateFileNo = logPartPtr.p->headFileNo; logPartPtr.p->invalidatePageNo = logPartPtr.p->headPageNo; logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_INVALIDATE; seizeLfo(signal); initLfo(signal); // The state here is a little confusing, but simulates that we return // to invalidateLogAfterLastGCI() from an invalidate write and are ready // to read a page from file. lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; invalidateLogAfterLastGCI(signal); return; }//Dblqh::readSrFourthZeroLab() /* -------------------------------------------------------------------------- * ONE OF THE LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART. * CHECK IF ALL LOG PARTS ARE COMPLETED. IF SO SEND START_RECCONF * ------------------------------------------------------------------------- */ void Dblqh::srFourthComp(Signal* signal) { jamEntry(); logPartPtr.i = signal->theData[0]; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_COMPLETED; for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { jam(); ptrAss(logPartPtr, logPartRecord); if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_COMPLETED) { if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_STARTED) { jam(); systemErrorLab(signal); return; } else { jam(); /* ------------------------------------------------------------------ * THIS LOG PART WAS NOT COMPLETED YET. * EXIT AND WAIT FOR IT TO COMPLETE * ----------------------------------------------------------------- */ return; }//if }//if }//for /* ------------------------------------------------------------------------ * ALL LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART. * WE CAN NOW SEND START_RECCONF TO THE MASTER DIH IF IT WAS A * SYSTEM RESTART. OTHERWISE WE WILL CONTINUE WITH AN INITIAL START. * SET LOG PART STATE TO IDLE TO * INDICATE THAT NOTHING IS GOING ON IN THE LOG PART. * ----------------------------------------------------------------------- */ for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { ptrAss(logPartPtr, logPartRecord); logPartPtr.p->logPartState = LogPartRecord::IDLE; }//for if ((cstartType == NodeState::ST_INITIAL_START) || (cstartType == NodeState::ST_INITIAL_NODE_RESTART)) { jam(); ndbrequire(cinitialStartOngoing == ZTRUE); cinitialStartOngoing = ZFALSE; checkStartCompletedLab(signal); return; } else if ((cstartType == NodeState::ST_NODE_RESTART) || (cstartType == NodeState::ST_SYSTEM_RESTART)) { jam(); StartRecConf * conf = (StartRecConf*)signal->getDataPtrSend(); conf->startingNodeId = getOwnNodeId(); sendSignal(cmasterDihBlockref, GSN_START_RECCONF, signal, StartRecConf::SignalLength, JBB); if(cstartType == NodeState::ST_SYSTEM_RESTART){ fragptr.i = c_redo_log_complete_frags; while(fragptr.i != RNIL){ ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); signal->theData[0] = fragptr.p->tabRef; signal->theData[1] = fragptr.p->fragId; sendSignal(DBACC_REF, GSN_EXPANDCHECK2, signal, 2, JBB); fragptr.i = fragptr.p->nextFrag; } } } else { ndbrequire(false); }//if return; }//Dblqh::srFourthComp() /* ######################################################################### */ /* ####### ERROR MODULE ####### */ /* */ /* ######################################################################### */ void Dblqh::warningHandlerLab(Signal* signal) { systemErrorLab(signal); return; }//Dblqh::warningHandlerLab() /*---------------------------------------------------------------------------*/ /* AN ERROR OCCURRED THAT WE WILL NOT TREAT AS SYSTEM ERROR. MOST OFTEN THIS */ /* WAS CAUSED BY AN ERRONEUS SIGNAL SENT BY ANOTHER NODE. WE DO NOT WISH TO */ /* CRASH BECAUSE OF FAULTS IN OTHER NODES. THUS WE ONLY REPORT A WARNING. */ /* THIS IS CURRENTLY NOT IMPLEMENTED AND FOR THE MOMENT WE GENERATE A SYSTEM */ /* ERROR SINCE WE WANT TO FIND FAULTS AS QUICKLY AS POSSIBLE IN A TEST PHASE.*/ /* IN A LATER PHASE WE WILL CHANGE THIS TO BE A WARNING MESSAGE INSTEAD. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* THIS TYPE OF ERROR SHOULD NOT GENERATE A SYSTEM ERROR IN A PRODUCT */ /* RELEASE. THIS IS A TEMPORARY SOLUTION DURING TEST PHASE TO QUICKLY */ /* FIND ERRORS. NORMALLY THIS SHOULD GENERATE A WARNING MESSAGE ONTO */ /* SOME ERROR LOGGER. THIS WILL LATER BE IMPLEMENTED BY SOME SIGNAL. */ /*---------------------------------------------------------------------------*/ /* ------ SYSTEM ERROR SITUATIONS ------- */ /* IN SITUATIONS WHERE THE STATE IS ERRONEOUS OR IF THE ERROR OCCURS IN */ /* THE COMMIT, COMPLETE OR ABORT PHASE, WE PERFORM A CRASH OF THE AXE VM*/ /*---------------------------------------------------------------------------*/ void Dblqh::systemErrorLab(Signal* signal) { progError(0, 0); /*************************************************************************>*/ /* WE WANT TO INVOKE AN IMMEDIATE ERROR HERE SO WE GET THAT BY */ /* INSERTING A CERTAIN POINTER OUT OF RANGE. */ /*************************************************************************>*/ }//Dblqh::systemErrorLab() /* ------- ERROR SITUATIONS ------- */ void Dblqh::aiStateErrorCheckLab(Signal* signal, Uint32* dataPtr, Uint32 length) { ndbrequire(tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE); if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) { jam(); /*************************************************************************>*/ /* TRANSACTION ABORT IS ONGOING. IT CAN STILL BE A PART OF AN */ /* OPERATION THAT SHOULD CONTINUE SINCE THE TUPLE HAS NOT ARRIVED */ /* YET. THIS IS POSSIBLE IF ACTIVE CREATION OF THE FRAGMENT IS */ /* ONGOING. */ /*************************************************************************>*/ if (tcConnectptr.p->activeCreat == ZTRUE) { jam(); /*************************************************************************>*/ /* ONGOING ABORTS DURING ACTIVE CREATION MUST SAVE THE ATTRIBUTE INFO*/ /* SO THAT IT CAN BE SENT TO THE NEXT NODE IN THE COMMIT CHAIN. THIS */ /* IS NEEDED SINCE ALL ABORTS DURING CREATION OF A FRAGMENT ARE NOT */ /* REALLY ERRORS. A MISSING TUPLE TO BE UPDATED SIMPLY MEANS THAT */ /* IT HASN'T BEEN TRANSFERRED TO THE NEW REPLICA YET. */ /*************************************************************************>*/ /*************************************************************************>*/ /* AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET */ /* ACTIVE CREATION TO FALSE. THIS WILL ENSURE THAT THE ABORT IS */ /* COMPLETED. */ /*************************************************************************>*/ if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { jam(); if (tcConnectptr.p->transactionState == TcConnectionrec::WAIT_AI_AFTER_ABORT) { if (tcConnectptr.p->currTupAiLen == tcConnectptr.p->totReclenAi) { jam(); /*************************************************************************>*/ /* WE WERE WAITING FOR MORE ATTRIBUTE INFO AFTER A SUCCESSFUL ABORT */ /* IN ACTIVE CREATION STATE. THE TRANSACTION SHOULD CONTINUE AS IF */ /* IT WAS COMMITTED. NOW ALL INFO HAS ARRIVED AND WE CAN CONTINUE */ /* WITH NORMAL PROCESSING AS IF THE TRANSACTION WAS PREPARED. */ /* SINCE THE FRAGMENT IS UNDER CREATION WE KNOW THAT LOGGING IS */ /* DISABLED. WE STILL HAVE TO CATER FOR DIRTY OPERATION OR NOT. */ /*************************************************************************>*/ tcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; rwConcludedAiLab(signal); return; } else { ndbrequire(tcConnectptr.p->currTupAiLen < tcConnectptr.p->totReclenAi); jam(); return; /* STILL WAITING FOR MORE ATTRIBUTE INFO */ }//if }//if } else { jam(); /*************************************************************************>*/ /* AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET */ /* ACTIVE CREATION TO ABORT. THIS WILL ENSURE THAT THE ABORT IS */ /* COMPLETED AND THAT THE ERROR CODE IS PROPERLY SET */ /*************************************************************************>*/ tcConnectptr.p->errorCode = terrorCode; tcConnectptr.p->activeCreat = ZFALSE; if (tcConnectptr.p->transactionState == TcConnectionrec::WAIT_AI_AFTER_ABORT) { jam(); /*************************************************************************>*/ /* ABORT IS ALREADY COMPLETED. WE NEED TO RESTART IT FROM WHERE IT */ /* WAS INTERRUPTED. */ /*************************************************************************>*/ continueAbortLab(signal); return; } else { jam(); return; /*************************************************************************>*/ // Abort is ongoing. It will complete since we set the activeCreat = ZFALSE /*************************************************************************>*/ }//if }//if }//if }//if /*************************************************************************>*/ /* TRANSACTION HAVE BEEN ABORTED. THUS IGNORE ALL SIGNALS BELONGING TO IT. */ /*************************************************************************>*/ return; }//Dblqh::aiStateErrorCheckLab() void Dblqh::takeOverErrorLab(Signal* signal) { terrorCode = ZTAKE_OVER_ERROR; abortErrorLab(signal); return; }//Dblqh::takeOverErrorLab() /* ########################################################################## * TEST MODULE * ######################################################################### */ #ifdef VM_TRACE void Dblqh::execTESTSIG(Signal* signal) { jamEntry(); Uint32 userpointer = signal->theData[0]; BlockReference userblockref = signal->theData[1]; Uint32 testcase = signal->theData[2]; signal->theData[0] = userpointer; signal->theData[1] = cownref; signal->theData[2] = testcase; sendSignal(userblockref, GSN_TESTSIG, signal, 25, JBB); return; }//Dblqh::execTESTSIG() /* *************** */ /* MEMCHECKREQ > */ /* *************** */ /* ************************************************************************>> * THIS SIGNAL IS PURELY FOR TESTING PURPOSES. IT CHECKS THE FREE LIST * AND REPORTS THE NUMBER OF FREE RECORDS. * THIS CAN BE DONE TO ENSURE THAT NO RECORDS HAS BEEN LOST * ************************************************************************> */ void Dblqh::execMEMCHECKREQ(Signal* signal) { Uint32* dataPtr = &signal->theData[0]; jamEntry(); BlockReference userblockref = signal->theData[0]; Uint32 index = 0; for (Uint32 i = 0; i < 7; i++) dataPtr[i] = 0; addfragptr.i = cfirstfreeAddfragrec; while (addfragptr.i != RNIL) { ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); addfragptr.i = addfragptr.p->nextAddfragrec; dataPtr[index]++; }//while index++; attrinbufptr.i = cfirstfreeAttrinbuf; while (attrinbufptr.i != RNIL) { ptrCheckGuard(attrinbufptr, cattrinbufFileSize, attrbuf); attrinbufptr.i = attrinbufptr.p->attrbuf[ZINBUF_NEXT]; dataPtr[index]++; }//while index++; databufptr.i = cfirstfreeDatabuf; while (databufptr.i != RNIL) { ptrCheckGuard(databufptr, cdatabufFileSize, databuf); databufptr.i = databufptr.p->nextDatabuf; dataPtr[index]++; }//while index++; fragptr.i = cfirstfreeFragrec; while (fragptr.i != RNIL) { ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.i = fragptr.p->nextFrag; dataPtr[index]++; }//while index++; for (tabptr.i = 0; tabptr.i < ctabrecFileSize; tabptr.i++) { ptrAss(tabptr, tablerec); if (tabptr.p->tableStatus == Tablerec::NOT_DEFINED) { dataPtr[index]++; }//if }//for index++; tcConnectptr.i = cfirstfreeTcConrec; while (tcConnectptr.i != RNIL) { ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); tcConnectptr.i = tcConnectptr.p->nextTcConnectrec; dataPtr[index]++; }//while sendSignal(userblockref, GSN_MEMCHECKCONF, signal, 10, JBB); return; }//Dblqh::execMEMCHECKREQ() #endif /* ************************************************************************* */ /* ************************* STATEMENT BLOCKS ****************************** */ /* ************************************************************************* */ /* ========================================================================= */ /* ====== BUILD LINKED LIST OF LOG PAGES AFTER RECEIVING FSREADCONF ======= */ /* */ /* ========================================================================= */ void Dblqh::buildLinkedLogPageList(Signal* signal) { LogPageRecordPtr bllLogPagePtr; arrGuard(lfoPtr.p->noPagesRw - 1, 16); arrGuard(lfoPtr.p->noPagesRw, 16); for (UintR tbllIndex = 0; tbllIndex < lfoPtr.p->noPagesRw; tbllIndex++) { jam(); /* ---------------------------------------------------------------------- * BUILD LINKED LIST BUT ALSO ENSURE THAT PAGE IS NOT SEEN AS DIRTY * INITIALLY. * --------------------------------------------------------------------- */ bllLogPagePtr.i = lfoPtr.p->logPageArray[tbllIndex]; ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord); // #if VM_TRACE // // Check logPage checksum before modifying it // Uint32 calcCheckSum = calcPageCheckSum(bllLogPagePtr); // Uint32 checkSum = bllLogPagePtr.p->logPageWord[ZPOS_CHECKSUM]; // if (checkSum != calcCheckSum) { // ndbout << "Redolog: Checksum failure." << endl; // progError(__LINE__, ERR_NDBREQUIRE, "Redolog: Checksum failure."); // } // #endif bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] = lfoPtr.p->logPageArray[tbllIndex + 1]; bllLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; }//for bllLogPagePtr.i = lfoPtr.p->logPageArray[lfoPtr.p->noPagesRw - 1]; ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord); bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; }//Dblqh::buildLinkedLogPageList() /* ========================================================================= * ======= CHANGE TO NEXT MBYTE IN LOG ======= * * ========================================================================= */ void Dblqh::changeMbyte(Signal* signal) { writeNextLog(signal); writeFileDescriptor(signal); }//Dblqh::changeMbyte() /* ========================================================================= */ /* ====== CHECK IF THIS COMMIT LOG RECORD IS TO BE EXECUTED ======= */ /* */ /* SUBROUTINE SHORT NAME = CEL */ /* ========================================================================= */ Uint32 Dblqh::checkIfExecLog(Signal* signal) { tabptr.i = tcConnectptr.p->tableref; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); if (getFragmentrec(signal, tcConnectptr.p->fragmentid) && (tabptr.p->schemaVersion == tcConnectptr.p->schemaVersion)) { if (fragptr.p->execSrStatus != Fragrecord::IDLE) { if (fragptr.p->execSrNoReplicas > logPartPtr.p->execSrExecuteIndex) { ndbrequire((fragptr.p->execSrNoReplicas - 1) < 4); for (Uint32 i = logPartPtr.p->execSrExecuteIndex; i < fragptr.p->execSrNoReplicas; i++) { jam(); if (tcConnectptr.p->gci >= fragptr.p->execSrStartGci[i]) { if (tcConnectptr.p->gci <= fragptr.p->execSrLastGci[i]) { jam(); logPartPtr.p->execSrExecuteIndex = i; return ZOK; }//if }//if }//for }//if }//if }//if return ZNOT_OK; }//Dblqh::checkIfExecLog() /* ========================================================================= */ /* == CHECK IF THERE IS LESS THAN 192 KBYTE IN THE BUFFER PLUS INCOMING === */ /* READS ALREADY STARTED. IF SO IS THE CASE THEN START ANOTHER READ IF */ /* THERE ARE MORE PAGES IN THIS MBYTE. */ /* */ /* ========================================================================= */ void Dblqh::checkReadExecSr(Signal* signal) { logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; logPartPtr.p->execSrPagesRead = logPartPtr.p->execSrPagesRead + 8; logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading - 8; if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesReading) < ZREAD_AHEAD_SIZE) { jam(); /* ---------------------------------------------------------------------- * WE HAVE LESS THAN 64 KBYTE OF LOG PAGES REMAINING IN MEMORY OR ON * ITS WAY TO MAIN MEMORY. READ IN 8 MORE PAGES. * --------------------------------------------------------------------- */ if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesExecuted) < ZPAGES_IN_MBYTE) { jam(); /* -------------------------------------------------------------------- * THERE ARE MORE PAGES TO READ IN THIS MBYTE. READ THOSE FIRST * IF >= ZPAGES_IN_MBYTE THEN THERE ARE NO MORE PAGES TO READ. THUS * WE PROCEED WITH EXECUTION OF THE LOG. * ------------------------------------------------------------------- */ readExecSr(signal); logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR; }//if }//if }//Dblqh::checkReadExecSr() /* ========================================================================= */ /* ==== CHECK IF START OF NEW FRAGMENT IS COMPLETED AND WE CAN ======= */ /* ==== GET THE START GCI ======= */ /* */ /* SUBROUTINE SHORT NAME = CTC */ /* ========================================================================= */ void Dblqh::checkScanTcCompleted(Signal* signal) { tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); fragptr.p->activeTcCounter = fragptr.p->activeTcCounter - 1; if (fragptr.p->activeTcCounter == 0) { jam(); fragptr.p->startGci = cnewestGci + 1; tabptr.i = tcConnectptr.p->tableref; ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); sendCopyActiveConf(signal, tcConnectptr.p->tableref); }//if }//Dblqh::checkScanTcCompleted() /* ========================================================================== * === CHECK IF ALL PARTS OF A SYSTEM RESTART ON A FRAGMENT ARE COMPLETED === * * SUBROUTINE SHORT NAME = CSC * ========================================================================= */ void Dblqh::checkSrCompleted(Signal* signal) { LcpLocRecordPtr cscLcpLocptr; terrorCode = ZOK; ptrGuard(lcpPtr); cscLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; CSC_ACC_DOWHILE: ptrCheckGuard(cscLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_COMPLETED) { jam(); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { jam(); systemErrorLab(signal); return; }//if return; }//if cscLcpLocptr.i = cscLcpLocptr.p->nextLcpLoc; if (cscLcpLocptr.i != RNIL) { jam(); goto CSC_ACC_DOWHILE; }//if cscLcpLocptr.i = lcpPtr.p->firstLcpLocTup; CSC_TUP_DOWHILE: ptrCheckGuard(cscLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_TUP_COMPLETED) { jam(); if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_TUP_STARTED) { jam(); systemErrorLab(signal); return; }//if return; }//if cscLcpLocptr.i = cscLcpLocptr.p->nextLcpLoc; if (cscLcpLocptr.i != RNIL) { jam(); goto CSC_TUP_DOWHILE; }//if lcpPtr.p->lcpState = LcpRecord::LCP_SR_COMPLETED; }//Dblqh::checkSrCompleted() /* ------------------------------------------------------------------------- */ /* ------ CLOSE A FILE DURING EXECUTION OF FRAGMENT LOG ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::closeFile(Signal* signal, LogFileRecordPtr clfLogFilePtr) { signal->theData[0] = clfLogFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = clfLogFilePtr.i; signal->theData[3] = ZCLOSE_NO_DELETE; sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA); }//Dblqh::closeFile() /* ---------------------------------------------------------------- */ /* ---------------- A LOG PAGE HAVE BEEN COMPLETED ---------------- */ /* */ /* SUBROUTINE SHORT NAME = CLP */ // Input Pointers: // logFilePtr // logPagePtr // logPartPtr // Defines lfoPtr /* ---------------------------------------------------------------- */ void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) { LogPageRecordPtr clpLogPagePtr; LogPageRecordPtr wlpLogPagePtr; UintR twlpNoPages; UintR twlpType; if (logFilePtr.p->firstFilledPage == RNIL) { jam(); logFilePtr.p->firstFilledPage = logPagePtr.i; } else { jam(); clpLogPagePtr.i = logFilePtr.p->lastFilledPage; ptrCheckGuard(clpLogPagePtr, clogPageFileSize, logPageRecord); clpLogPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i; }//if logFilePtr.p->lastFilledPage = logPagePtr.i; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; logFilePtr.p->noLogpagesInBuffer = logFilePtr.p->noLogpagesInBuffer + 1; if (logFilePtr.p->noLogpagesInBuffer != ZMAX_PAGES_WRITTEN) { if (clpType != ZLAST_WRITE_IN_FILE) { if (clpType != ZENFORCE_WRITE) { jam(); return; }//if }//if }//if twlpType = clpType; /* ------------------------------------------------------------------------- */ /* ------ WRITE A SET OF LOG PAGES TO DISK ------- */ /* */ /* SUBROUTINE SHORT NAME: WLP */ /* ------------------------------------------------------------------------- */ seizeLfo(signal); initLfo(signal); Uint32* dataPtr = &signal->theData[6]; twlpNoPages = 0; wlpLogPagePtr.i = logFilePtr.p->firstFilledPage; do { dataPtr[twlpNoPages] = wlpLogPagePtr.i; twlpNoPages++; ptrCheckGuard(wlpLogPagePtr, clogPageFileSize, logPageRecord); // Calculate checksum for page wlpLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(wlpLogPagePtr); wlpLogPagePtr.i = wlpLogPagePtr.p->logPageWord[ZNEXT_PAGE]; } while (wlpLogPagePtr.i != RNIL); ndbrequire(twlpNoPages < 9); dataPtr[twlpNoPages] = logFilePtr.p->filePosition; /* -------------------------------------------------- */ /* SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */ /* LOG RECORD HAS BEEN SENT AT THIS TIME. */ /* -------------------------------------------------- */ logPartPtr.p->logPartTimer = logPartPtr.p->logTimer; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; logFilePtr.p->logFilePagesToDiskWithoutSynch += twlpNoPages; if (twlpType == ZLAST_WRITE_IN_FILE) { jam(); logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; signal->theData[3] = ZLIST_OF_MEM_PAGES_SYNCH; } else if (logFilePtr.p->logFilePagesToDiskWithoutSynch > MAX_REDO_PAGES_WITHOUT_SYNCH) { jam(); logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; signal->theData[3] = ZLIST_OF_MEM_PAGES_SYNCH; } else { jam(); signal->theData[3] = ZLIST_OF_MEM_PAGES; }//if signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = twlpNoPages; sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 15, JBA); if (twlpType == ZNORMAL) { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; } else if (twlpType == ZLAST_WRITE_IN_FILE) { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::LAST_WRITE_IN_FILE; } else { ndbrequire(twlpType == ZENFORCE_WRITE); jam(); lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; }//if /* ----------------------------------------------------------------------- */ /* ------ MOVE PAGES FROM LOG FILE TO LFO RECORD ------- */ /* */ /* ----------------------------------------------------------------------- */ /* -------------------------------------------------- */ /* MOVE PAGES TO LFO RECORD AND REMOVE THEM */ /* FROM LOG FILE RECORD. */ /* -------------------------------------------------- */ lfoPtr.p->firstLfoPage = logFilePtr.p->firstFilledPage; logFilePtr.p->firstFilledPage = RNIL; logFilePtr.p->lastFilledPage = RNIL; logFilePtr.p->noLogpagesInBuffer = 0; lfoPtr.p->noPagesRw = twlpNoPages; lfoPtr.p->lfoPageNo = logFilePtr.p->filePosition; lfoPtr.p->lfoWordWritten = ZPAGE_SIZE - 1; logFilePtr.p->filePosition += twlpNoPages; }//Dblqh::completedLogPage() /* ---------------------------------------------------------------- */ /* ---------------- DELETE FRAGMENT RECORD ------------------------ */ /* */ /* SUBROUTINE SHORT NAME = DFR */ /* ---------------------------------------------------------------- */ void Dblqh::deleteFragrec(Uint32 fragId) { Uint32 indexFound= RNIL; fragptr.i = RNIL; for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { jam(); if (tabptr.p->fragid[i] == fragId) { fragptr.i = tabptr.p->fragrec[i]; indexFound = i; break; }//if }//for if (fragptr.i != RNIL) { jam(); ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); tabptr.p->fragid[indexFound] = ZNIL; tabptr.p->fragrec[indexFound] = RNIL; releaseFragrec(); }//if }//Dblqh::deleteFragrec() /* ------------------------------------------------------------------------- */ /* ------- FIND LOG FILE RECORD GIVEN FILE NUMBER ------- */ /* */ /* INPUT: TFLF_FILE_NO THE FILE NUMBER */ /* FLF_LOG_PART_PTR THE LOG PART RECORD */ /* OUTPUT: FLF_LOG_FILE_PTR THE FOUND LOG FILE RECORD */ /* SUBROUTINE SHORT NAME = FLF */ /* ------------------------------------------------------------------------- */ void Dblqh::findLogfile(Signal* signal, Uint32 fileNo, LogPartRecordPtr flfLogPartPtr, LogFileRecordPtr* parLogFilePtr) { LogFileRecordPtr locLogFilePtr; locLogFilePtr.i = flfLogPartPtr.p->firstLogfile; Uint32 loopCount = 0; while (true) { ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); if (locLogFilePtr.p->fileNo == fileNo) { jam(); ndbrequire(loopCount == fileNo); parLogFilePtr->i = locLogFilePtr.i; parLogFilePtr->p = locLogFilePtr.p; return; }//if locLogFilePtr.i = locLogFilePtr.p->nextLogFile; loopCount++; ndbrequire(loopCount < flfLogPartPtr.p->noLogFiles); }//while }//Dblqh::findLogfile() /* ------------------------------------------------------------------------- */ /* ------ FIND PAGE REFERENCE IN MEMORY BUFFER AT LOG EXECUTION ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::findPageRef(Signal* signal, CommitLogRecord* commitLogRecord) { UintR tfprIndex; logPagePtr.i = RNIL; if (ERROR_INSERTED(5020)) { // Force system to read page from disk return; } pageRefPtr.i = logPartPtr.p->lastPageRef; do { ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); if (commitLogRecord->fileNo == pageRefPtr.p->prFileNo) { if (commitLogRecord->startPageNo >= pageRefPtr.p->prPageNo) { if (commitLogRecord->startPageNo < (Uint16) (pageRefPtr.p->prPageNo + 8)) { jam(); tfprIndex = commitLogRecord->startPageNo - pageRefPtr.p->prPageNo; logPagePtr.i = pageRefPtr.p->pageRef[tfprIndex]; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); return; }//if }//if }//if pageRefPtr.i = pageRefPtr.p->prPrev; } while (pageRefPtr.i != RNIL); }//Dblqh::findPageRef() /* ------------------------------------------------------------------------- */ /* ------ GET FIRST OPERATION QUEUED FOR LOGGING ------- */ /* */ /* SUBROUTINE SHORT NAME = GFL */ /* ------------------------------------------------------------------------- */ void Dblqh::getFirstInLogQueue(Signal* signal) { TcConnectionrecPtr gflTcConnectptr; /* -------------------------------------------------- */ /* GET THE FIRST FROM THE LOG QUEUE AND REMOVE */ /* IT FROM THE QUEUE. */ /* -------------------------------------------------- */ gflTcConnectptr.i = logPartPtr.p->firstLogQueue; ptrCheckGuard(gflTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); logPartPtr.p->firstLogQueue = gflTcConnectptr.p->nextTcLogQueue; if (logPartPtr.p->firstLogQueue == RNIL) { jam(); logPartPtr.p->lastLogQueue = RNIL; }//if }//Dblqh::getFirstInLogQueue() /* ---------------------------------------------------------------- */ /* ---------------- GET FRAGMENT RECORD --------------------------- */ /* INPUT: TFRAGID FRAGMENT ID LOOKING FOR */ /* TABPTR TABLE ID */ /* SUBROUTINE SHORT NAME = GFR */ /* ---------------------------------------------------------------- */ bool Dblqh::getFragmentrec(Signal* signal, Uint32 fragId) { for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (UintR)~i; i--) { jam(); if (tabptr.p->fragid[i] == fragId) { fragptr.i = tabptr.p->fragrec[i]; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); return true; }//if }//for return false; }//Dblqh::getFragmentrec() /* ========================================================================= */ /* ====== INITIATE FRAGMENT RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseAddfragrec(Signal* signal) { if (caddfragrecFileSize != 0) { for (addfragptr.i = 0; addfragptr.i < caddfragrecFileSize; addfragptr.i++) { ptrAss(addfragptr, addFragRecord); addfragptr.p->addfragStatus = AddFragRecord::FREE; addfragptr.p->nextAddfragrec = addfragptr.i + 1; }//for addfragptr.i = caddfragrecFileSize - 1; ptrAss(addfragptr, addFragRecord); addfragptr.p->nextAddfragrec = RNIL; cfirstfreeAddfragrec = 0; } else { jam(); cfirstfreeAddfragrec = RNIL; }//if }//Dblqh::initialiseAddfragrec() /* ========================================================================= */ /* ====== INITIATE ATTRIBUTE IN AND OUT DATA BUFFER ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseAttrbuf(Signal* signal) { if (cattrinbufFileSize != 0) { for (attrinbufptr.i = 0; attrinbufptr.i < cattrinbufFileSize; attrinbufptr.i++) { refresh_watch_dog(); ptrAss(attrinbufptr, attrbuf); attrinbufptr.p->attrbuf[ZINBUF_NEXT] = attrinbufptr.i + 1; }//for /* NEXT ATTRINBUF */ attrinbufptr.i = cattrinbufFileSize - 1; ptrAss(attrinbufptr, attrbuf); attrinbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL; /* NEXT ATTRINBUF */ cfirstfreeAttrinbuf = 0; } else { jam(); cfirstfreeAttrinbuf = RNIL; }//if }//Dblqh::initialiseAttrbuf() /* ========================================================================= */ /* ====== INITIATE DATA BUFFER ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseDatabuf(Signal* signal) { if (cdatabufFileSize != 0) { for (databufptr.i = 0; databufptr.i < cdatabufFileSize; databufptr.i++) { refresh_watch_dog(); ptrAss(databufptr, databuf); databufptr.p->nextDatabuf = databufptr.i + 1; }//for databufptr.i = cdatabufFileSize - 1; ptrAss(databufptr, databuf); databufptr.p->nextDatabuf = RNIL; cfirstfreeDatabuf = 0; } else { jam(); cfirstfreeDatabuf = RNIL; }//if }//Dblqh::initialiseDatabuf() /* ========================================================================= */ /* ====== INITIATE FRAGMENT RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseFragrec(Signal* signal) { if (cfragrecFileSize != 0) { for (fragptr.i = 0; fragptr.i < cfragrecFileSize; fragptr.i++) { refresh_watch_dog(); ptrAss(fragptr, fragrecord); fragptr.p->fragStatus = Fragrecord::FREE; fragptr.p->fragActiveStatus = ZFALSE; fragptr.p->execSrStatus = Fragrecord::IDLE; fragptr.p->srStatus = Fragrecord::SS_IDLE; fragptr.p->nextFrag = fragptr.i + 1; }//for fragptr.i = cfragrecFileSize - 1; ptrAss(fragptr, fragrecord); fragptr.p->nextFrag = RNIL; cfirstfreeFragrec = 0; } else { jam(); cfirstfreeFragrec = RNIL; }//if }//Dblqh::initialiseFragrec() /* ========================================================================= */ /* ====== INITIATE FRAGMENT RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseGcprec(Signal* signal) { UintR tigpIndex; if (cgcprecFileSize != 0) { for (gcpPtr.i = 0; gcpPtr.i < cgcprecFileSize; gcpPtr.i++) { ptrAss(gcpPtr, gcpRecord); for (tigpIndex = 0; tigpIndex <= 3; tigpIndex++) { gcpPtr.p->gcpLogPartState[tigpIndex] = ZIDLE; gcpPtr.p->gcpSyncReady[tigpIndex] = ZFALSE; }//for }//for }//if }//Dblqh::initialiseGcprec() /* ========================================================================= */ /* ====== INITIATE LCP RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseLcpRec(Signal* signal) { if (clcpFileSize != 0) { for (lcpPtr.i = 0; lcpPtr.i < clcpFileSize; lcpPtr.i++) { ptrAss(lcpPtr, lcpRecord); lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; lcpPtr.p->lcpQueued = false; lcpPtr.p->firstLcpLocAcc = RNIL; lcpPtr.p->firstLcpLocTup = RNIL; lcpPtr.p->reportEmpty = false; lcpPtr.p->lastFragmentFlag = false; }//for }//if }//Dblqh::initialiseLcpRec() /* ========================================================================= */ /* ====== INITIATE LCP LOCAL RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseLcpLocrec(Signal* signal) { if (clcpLocrecFileSize != 0) { for (lcpLocptr.i = 0; lcpLocptr.i < clcpLocrecFileSize; lcpLocptr.i++) { ptrAss(lcpLocptr, lcpLocRecord); lcpLocptr.p->nextLcpLoc = lcpLocptr.i + 1; lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; lcpLocptr.p->masterLcpRec = RNIL; lcpLocptr.p->waitingBlock = LcpLocRecord::NONE; }//for lcpLocptr.i = clcpLocrecFileSize - 1; ptrAss(lcpLocptr, lcpLocRecord); lcpLocptr.p->nextLcpLoc = RNIL; cfirstfreeLcpLoc = 0; } else { jam(); cfirstfreeLcpLoc = RNIL; }//if }//Dblqh::initialiseLcpLocrec() /* ========================================================================= */ /* ====== INITIATE LOG FILE OPERATION RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseLfo(Signal* signal) { if (clfoFileSize != 0) { for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) { ptrAss(lfoPtr, logFileOperationRecord); lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; lfoPtr.p->lfoTimer = 0; lfoPtr.p->nextLfo = lfoPtr.i + 1; }//for lfoPtr.i = clfoFileSize - 1; ptrAss(lfoPtr, logFileOperationRecord); lfoPtr.p->nextLfo = RNIL; cfirstfreeLfo = 0; } else { jam(); cfirstfreeLfo = RNIL; }//if }//Dblqh::initialiseLfo() /* ========================================================================= */ /* ====== INITIATE LOG FILE RECORD ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseLogFile(Signal* signal) { if (clogFileFileSize != 0) { for (logFilePtr.i = 0; logFilePtr.i < clogFileFileSize; logFilePtr.i++) { ptrAss(logFilePtr, logFileRecord); logFilePtr.p->nextLogFile = logFilePtr.i + 1; logFilePtr.p->logFileStatus = LogFileRecord::LFS_IDLE; }//for logFilePtr.i = clogFileFileSize - 1; ptrAss(logFilePtr, logFileRecord); logFilePtr.p->nextLogFile = RNIL; cfirstfreeLogFile = 0; } else { jam(); cfirstfreeLogFile = RNIL; }//if }//Dblqh::initialiseLogFile() /* ========================================================================= */ /* ====== INITIATE LOG PAGES ======= */ /* */ /* ========================================================================= */ void Dblqh::initialiseLogPage(Signal* signal) { if (clogPageFileSize != 0) { for (logPagePtr.i = 0; logPagePtr.i < clogPageFileSize; logPagePtr.i++) { refresh_watch_dog(); ptrAss(logPagePtr, logPageRecord); logPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i + 1; }//for logPagePtr.i = clogPageFileSize - 1; ptrAss(logPagePtr, logPageRecord); logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; cfirstfreeLogPage = 0; } else { jam(); cfirstfreeLogPage = RNIL; }//if cnoOfLogPages = clogPageFileSize; }//Dblqh::initialiseLogPage() /* ========================================================================= * ====== INITIATE LOG PART RECORD ======= * * ========================================================================= */ void Dblqh::initialiseLogPart(Signal* signal) { for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { ptrAss(logPartPtr, logPartRecord); logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; logPartPtr.p->LogLqhKeyReqSent = ZFALSE; logPartPtr.p->logPartNewestCompletedGCI = (UintR)-1; }//for }//Dblqh::initialiseLogPart() void Dblqh::initialisePageRef(Signal* signal) { if (cpageRefFileSize != 0) { for (pageRefPtr.i = 0; pageRefPtr.i < cpageRefFileSize; pageRefPtr.i++) { ptrAss(pageRefPtr, pageRefRecord); pageRefPtr.p->prNext = pageRefPtr.i + 1; }//for pageRefPtr.i = cpageRefFileSize - 1; ptrAss(pageRefPtr, pageRefRecord); pageRefPtr.p->prNext = RNIL; cfirstfreePageRef = 0; } else { jam(); cfirstfreePageRef = RNIL; }//if }//Dblqh::initialisePageRef() /* ========================================================================== * ======= INITIATE RECORDS ======= * * TAKES CARE OF INITIATION OF ALL RECORDS IN THIS BLOCK. * ========================================================================= */ void Dblqh::initialiseRecordsLab(Signal* signal, Uint32 data, Uint32 retRef, Uint32 retData) { Uint32 i; switch (data) { case 0: jam(); for (i = 0; i < MAX_NDB_NODES; i++) { cnodeSrState[i] = ZSTART_SR; cnodeExecSrState[i] = ZSTART_SR; }//for for (i = 0; i < 1024; i++) { ctransidHash[i] = RNIL; }//for for (i = 0; i < 4; i++) { cactiveCopy[i] = RNIL; }//for cnoActiveCopy = 0; cCounterAccCommitBlocked = 0; cCounterTupCommitBlocked = 0; caccCommitBlocked = false; ctupCommitBlocked = false; cCommitBlocked = false; ccurrentGcprec = RNIL; caddNodeState = ZFALSE; cstartRecReq = ZFALSE; cnewestGci = (UintR)-1; cnewestCompletedGci = (UintR)-1; crestartOldestGci = 0; crestartNewestGci = 0; cfirstWaitFragSr = RNIL; cfirstCompletedFragSr = RNIL; csrPhaseStarted = ZSR_NO_PHASE_STARTED; csrPhasesCompleted = 0; cmasterDihBlockref = 0; cnoFragmentsExecSr = 0; clcpCompletedState = LCP_IDLE; csrExecUndoLogState = EULS_IDLE; c_lcpId = 0; cnoOfFragsCheckpointed = 0; break; case 1: jam(); initialiseAddfragrec(signal); break; case 2: jam(); initialiseAttrbuf(signal); break; case 3: jam(); initialiseDatabuf(signal); break; case 4: jam(); initialiseFragrec(signal); break; case 5: jam(); initialiseGcprec(signal); initialiseLcpRec(signal); initialiseLcpLocrec(signal); break; case 6: jam(); initialiseLogPage(signal); break; case 7: jam(); initialiseLfo(signal); break; case 8: jam(); initialiseLogFile(signal); initialiseLogPart(signal); break; case 9: jam(); initialisePageRef(signal); break; case 10: jam(); initialiseScanrec(signal); break; case 11: jam(); initialiseTabrec(signal); break; case 12: jam(); initialiseTcNodeFailRec(signal); initialiseTcrec(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: ndbrequire(false); break; }//switch signal->theData[0] = ZINITIALISE_RECORDS; signal->theData[1] = data + 1; signal->theData[2] = 0; signal->theData[3] = retRef; signal->theData[4] = retData; sendSignal(DBLQH_REF, GSN_CONTINUEB, signal, 5, JBB); return; }//Dblqh::initialiseRecordsLab() /* ========================================================================== * ======= INITIATE TC CONNECTION RECORD ======= * * ========================================================================= */ void Dblqh::initialiseScanrec(Signal* signal) { ndbrequire(cscanrecFileSize > 1); DLList<ScanRecord> tmp(c_scanRecordPool); while (tmp.seize(scanptr)){ //new (scanptr.p) ScanRecord(); refresh_watch_dog(); scanptr.p->scanType = ScanRecord::ST_IDLE; scanptr.p->scanState = ScanRecord::SCAN_FREE; scanptr.p->scanTcWaiting = ZFALSE; scanptr.p->nextHash = RNIL; scanptr.p->prevHash = RNIL; scanptr.p->scan_acc_index= 0; scanptr.p->scan_acc_attr_recs= 0; } tmp.release(); }//Dblqh::initialiseScanrec() /* ========================================================================== * ======= INITIATE TABLE RECORD ======= * * ========================================================================= */ void Dblqh::initialiseTabrec(Signal* signal) { if (ctabrecFileSize != 0) { for (tabptr.i = 0; tabptr.i < ctabrecFileSize; tabptr.i++) { refresh_watch_dog(); ptrAss(tabptr, tablerec); tabptr.p->tableStatus = Tablerec::NOT_DEFINED; tabptr.p->usageCount = 0; for (Uint32 i = 0; i <= (MAX_FRAG_PER_NODE - 1); i++) { tabptr.p->fragid[i] = ZNIL; tabptr.p->fragrec[i] = RNIL; }//for }//for }//if }//Dblqh::initialiseTabrec() /* ========================================================================== * ======= INITIATE TC CONNECTION RECORD ======= * * ========================================================================= */ void Dblqh::initialiseTcrec(Signal* signal) { if (ctcConnectrecFileSize != 0) { for (tcConnectptr.i = 0; tcConnectptr.i < ctcConnectrecFileSize; tcConnectptr.i++) { refresh_watch_dog(); ptrAss(tcConnectptr, tcConnectionrec); tcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; tcConnectptr.p->tcScanRec = RNIL; tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED; tcConnectptr.p->firstAttrinbuf = RNIL; tcConnectptr.p->lastAttrinbuf = RNIL; tcConnectptr.p->firstTupkeybuf = RNIL; tcConnectptr.p->lastTupkeybuf = RNIL; tcConnectptr.p->tcTimer = 0; tcConnectptr.p->nextTcConnectrec = tcConnectptr.i + 1; }//for tcConnectptr.i = ctcConnectrecFileSize - 1; ptrAss(tcConnectptr, tcConnectionrec); tcConnectptr.p->nextTcConnectrec = RNIL; cfirstfreeTcConrec = 0; } else { jam(); cfirstfreeTcConrec = RNIL; }//if }//Dblqh::initialiseTcrec() /* ========================================================================== * ======= INITIATE TC CONNECTION RECORD ======= * * ========================================================================= */ void Dblqh::initialiseTcNodeFailRec(Signal* signal) { if (ctcNodeFailrecFileSize != 0) { for (tcNodeFailptr.i = 0; tcNodeFailptr.i < ctcNodeFailrecFileSize; tcNodeFailptr.i++) { ptrAss(tcNodeFailptr, tcNodeFailRecord); tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE; }//for }//if }//Dblqh::initialiseTcNodeFailRec() /* ========================================================================== * ======= INITIATE FRAGMENT RECORD ======= * * SUBROUTINE SHORT NAME = IF * ========================================================================= */ void Dblqh::initFragrec(Signal* signal, Uint32 tableId, Uint32 fragId, Uint32 copyType) { new (fragptr.p) Fragrecord(); fragptr.p->m_scanNumberMask.set(); // All is free fragptr.p->accBlockref = caccBlockref; fragptr.p->accBlockedList = RNIL; fragptr.p->activeList = RNIL; fragptr.p->firstWaitQueue = RNIL; fragptr.p->lastWaitQueue = RNIL; fragptr.p->fragStatus = Fragrecord::DEFINED; fragptr.p->fragCopy = copyType; fragptr.p->tupBlockref = ctupBlockref; fragptr.p->tuxBlockref = ctuxBlockref; fragptr.p->lcpRef = RNIL; fragptr.p->logFlag = Fragrecord::STATE_TRUE; fragptr.p->lcpFlag = Fragrecord::LCP_STATE_TRUE; for (Uint32 i = 0; i < MAX_LCP_STORED; i++) { fragptr.p->lcpId[i] = 0; }//for fragptr.p->maxGciCompletedInLcp = 0; fragptr.p->maxGciInLcp = 0; fragptr.p->copyFragState = ZIDLE; fragptr.p->nextFrag = RNIL; fragptr.p->newestGci = cnewestGci; fragptr.p->nextLcp = 0; fragptr.p->tabRef = tableId; fragptr.p->fragId = fragId; fragptr.p->srStatus = Fragrecord::SS_IDLE; fragptr.p->execSrStatus = Fragrecord::IDLE; fragptr.p->execSrNoReplicas = 0; fragptr.p->fragDistributionKey = 0; fragptr.p->activeTcCounter = 0; fragptr.p->tableFragptr = RNIL; }//Dblqh::initFragrec() /* ========================================================================== * ======= INITIATE FRAGMENT RECORD FOR SYSTEM RESTART ======= * * SUBROUTINE SHORT NAME = IFS * ========================================================================= */ void Dblqh::initFragrecSr(Signal* signal) { const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; Uint32 lcpNo = startFragReq->lcpNo; Uint32 noOfLogNodes = startFragReq->noOfLogNodes; ndbrequire(noOfLogNodes <= 4); fragptr.p->fragStatus = Fragrecord::CRASH_RECOVERING; fragptr.p->srBlockref = startFragReq->userRef; fragptr.p->srUserptr = startFragReq->userPtr; fragptr.p->srChkpnr = lcpNo; if (lcpNo == (MAX_LCP_STORED - 1)) { jam(); fragptr.p->lcpId[lcpNo] = startFragReq->lcpId; fragptr.p->nextLcp = 0; } else if (lcpNo < (MAX_LCP_STORED - 1)) { jam(); fragptr.p->lcpId[lcpNo] = startFragReq->lcpId; fragptr.p->nextLcp = lcpNo + 1; } else { ndbrequire(lcpNo == ZNIL); jam(); fragptr.p->nextLcp = 0; }//if fragptr.p->srNoLognodes = noOfLogNodes; fragptr.p->logFlag = Fragrecord::STATE_FALSE; fragptr.p->srStatus = Fragrecord::SS_IDLE; if (noOfLogNodes > 0) { jam(); for (Uint32 i = 0; i < noOfLogNodes; i++) { jam(); fragptr.p->srStartGci[i] = startFragReq->startGci[i]; fragptr.p->srLastGci[i] = startFragReq->lastGci[i]; fragptr.p->srLqhLognode[i] = startFragReq->lqhLogNode[i]; }//for fragptr.p->newestGci = startFragReq->lastGci[noOfLogNodes - 1]; } else { fragptr.p->newestGci = cnewestGci; }//if }//Dblqh::initFragrecSr() /* ========================================================================== * ======= INITIATE INFORMATION ABOUT GLOBAL CHECKPOINTS ======= * IN LOG FILE RECORDS * * INPUT: LOG_FILE_PTR CURRENT LOG FILE * TNO_FD_DESCRIPTORS THE NUMBER OF FILE DESCRIPTORS * TO READ FROM THE LOG PAGE * LOG_PAGE_PTR PAGE ZERO IN LOG FILE * SUBROUTINE SHORT NAME = IGL * ========================================================================= */ void Dblqh::initGciInLogFileRec(Signal* signal, Uint32 noFdDescriptors) { LogFileRecordPtr iglLogFilePtr; UintR tiglLoop; UintR tiglIndex; tiglLoop = 0; iglLogFilePtr.i = logFilePtr.i; iglLogFilePtr.p = logFilePtr.p; IGL_LOOP: for (tiglIndex = 0; tiglIndex <= ZNO_MBYTES_IN_FILE - 1; tiglIndex++) { arrGuard(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex, ZPAGE_SIZE); iglLogFilePtr.p->logMaxGciCompleted[tiglIndex] = logPagePtr.p->logPageWord[((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + ZNO_MBYTES_IN_FILE) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex, ZPAGE_SIZE); iglLogFilePtr.p->logMaxGciStarted[tiglIndex] = logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + ZNO_MBYTES_IN_FILE) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (2 * ZNO_MBYTES_IN_FILE)) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex, ZPAGE_SIZE); iglLogFilePtr.p->logLastPrepRef[tiglIndex] = logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + (2 * ZNO_MBYTES_IN_FILE)) + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; }//for tiglLoop = tiglLoop + 1; if (tiglLoop < noFdDescriptors) { jam(); iglLogFilePtr.i = iglLogFilePtr.p->prevLogFile; ptrCheckGuard(iglLogFilePtr, clogFileFileSize, logFileRecord); goto IGL_LOOP; }//if }//Dblqh::initGciInLogFileRec() /* ========================================================================== * ======= INITIATE LCP RECORD WHEN USED FOR SYSTEM RESTART ======= * * SUBROUTINE SHORT NAME = ILS * ========================================================================= */ void Dblqh::initLcpSr(Signal* signal, Uint32 lcpNo, Uint32 lcpId, Uint32 tableId, Uint32 fragId, Uint32 fragPtr) { lcpPtr.p->lcpQueued = false; lcpPtr.p->currentFragment.fragPtrI = fragPtr; lcpPtr.p->currentFragment.lcpFragOrd.lcpNo = lcpNo; lcpPtr.p->currentFragment.lcpFragOrd.lcpId = lcpId; lcpPtr.p->currentFragment.lcpFragOrd.tableId = tableId; lcpPtr.p->currentFragment.lcpFragOrd.fragmentId = fragId; lcpPtr.p->lcpState = LcpRecord::LCP_SR_WAIT_FRAGID; lcpPtr.p->firstLcpLocAcc = RNIL; lcpPtr.p->firstLcpLocTup = RNIL; lcpPtr.p->lcpAccptr = RNIL; }//Dblqh::initLcpSr() /* ========================================================================== * ======= INITIATE LOG PART ======= * * ========================================================================= */ void Dblqh::initLogpart(Signal* signal) { logPartPtr.p->execSrLogPage = RNIL; logPartPtr.p->execSrLogPageIndex = ZNIL; logPartPtr.p->execSrExecuteIndex = 0; logPartPtr.p->noLogFiles = cnoLogFiles; logPartPtr.p->logLap = 0; logPartPtr.p->logTailFileNo = 0; logPartPtr.p->logTailMbyte = 0; logPartPtr.p->lastMbyte = ZNIL; logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE; logPartPtr.p->logExecState = LogPartRecord::LES_IDLE; logPartPtr.p->firstLogTcrec = RNIL; logPartPtr.p->lastLogTcrec = RNIL; logPartPtr.p->firstLogQueue = RNIL; logPartPtr.p->lastLogQueue = RNIL; logPartPtr.p->gcprec = RNIL; logPartPtr.p->firstPageRef = RNIL; logPartPtr.p->lastPageRef = RNIL; logPartPtr.p->headFileNo = ZNIL; logPartPtr.p->headPageNo = ZNIL; logPartPtr.p->headPageIndex = ZNIL; }//Dblqh::initLogpart() /* ========================================================================== * ======= INITIATE LOG POINTERS ======= * * ========================================================================= */ void Dblqh::initLogPointers(Signal* signal) { logPartPtr.i = tcConnectptr.p->hashValue & 3; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logFilePtr.i = logPartPtr.p->currentLogfile; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); }//Dblqh::initLogPointers() /* ------------------------------------------------------------------------- */ /* ------- INIT REQUEST INFO BEFORE EXECUTING A LOG RECORD ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::initReqinfoExecSr(Signal* signal) { UintR Treqinfo = 0; TcConnectionrec * const regTcPtr = tcConnectptr.p; LqhKeyReq::setKeyLen(Treqinfo, regTcPtr->primKeyLen); /* ------------------------------------------------------------------------- */ /* NUMBER OF BACKUPS AND STANDBYS ARE ZERO AND NEED NOT BE SET. */ /* REPLICA TYPE IS CLEARED BY SEND_LQHKEYREQ. */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* SET LAST REPLICA NUMBER TO ZERO (BIT 10-11) */ /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ /* SET DIRTY FLAG */ /* ------------------------------------------------------------------------- */ LqhKeyReq::setDirtyFlag(Treqinfo, 1); /* ------------------------------------------------------------------------- */ /* SET SIMPLE TRANSACTION */ /* ------------------------------------------------------------------------- */ LqhKeyReq::setSimpleFlag(Treqinfo, 1); /* ------------------------------------------------------------------------- */ /* SET OPERATION TYPE AND LOCK MODE (NEVER READ OPERATION OR SCAN IN LOG) */ /* ------------------------------------------------------------------------- */ LqhKeyReq::setLockType(Treqinfo, regTcPtr->operation); LqhKeyReq::setOperation(Treqinfo, regTcPtr->operation); regTcPtr->reqinfo = Treqinfo; /* ------------------------------------------------------------------------ */ /* NO OF BACKUP IS SET TO ONE AND NUMBER OF STANDBY NODES IS SET TO ZERO. */ /* THUS THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL */ /* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET. */ /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------- */ /* SET REPLICA TYPE TO PRIMARY AND NUMBER OF REPLICA TO ONE */ /* ------------------------------------------------------------------------- */ regTcPtr->lastReplicaNo = 0; regTcPtr->apiVersionNo = 0; regTcPtr->nextSeqNoReplica = 0; regTcPtr->opExec = 0; regTcPtr->storedProcId = ZNIL; regTcPtr->readlenAi = 0; regTcPtr->nodeAfterNext[0] = ZNIL; regTcPtr->nodeAfterNext[1] = ZNIL; regTcPtr->dirtyOp = ZFALSE; regTcPtr->tcBlockref = cownref; }//Dblqh::initReqinfoExecSr() /* -------------------------------------------------------------------------- * ------- INSERT FRAGMENT ------- * * ------------------------------------------------------------------------- */ bool Dblqh::insertFragrec(Signal* signal, Uint32 fragId) { terrorCode = ZOK; if (cfirstfreeFragrec == RNIL) { jam(); terrorCode = ZNO_FREE_FRAGMENTREC; return false; }//if seizeFragmentrec(signal); for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { jam(); if (tabptr.p->fragid[i] == ZNIL) { jam(); tabptr.p->fragid[i] = fragId; tabptr.p->fragrec[i] = fragptr.i; return true; }//if }//for terrorCode = ZTOO_MANY_FRAGMENTS; return false; }//Dblqh::insertFragrec() /* -------------------------------------------------------------------------- * ------- LINK OPERATION IN ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME: LFQ // Input Pointers: // tcConnectptr // fragptr * ------------------------------------------------------------------------- */ void Dblqh::linkFragQueue(Signal* signal) { TcConnectionrecPtr lfqTcConnectptr; TcConnectionrec * const regTcPtr = tcConnectptr.p; Fragrecord * const regFragPtr = fragptr.p; Uint32 tcIndex = tcConnectptr.i; lfqTcConnectptr.i = regFragPtr->lastWaitQueue; regTcPtr->nextTc = RNIL; regFragPtr->lastWaitQueue = tcIndex; regTcPtr->prevTc = lfqTcConnectptr.i; ndbrequire(regTcPtr->listState == TcConnectionrec::NOT_IN_LIST); regTcPtr->listState = TcConnectionrec::WAIT_QUEUE_LIST; if (lfqTcConnectptr.i != RNIL) { jam(); ptrCheckGuard(lfqTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); lfqTcConnectptr.p->nextTc = tcIndex; } else { regFragPtr->firstWaitQueue = tcIndex; }//if return; }//Dblqh::linkFragQueue() /* ------------------------------------------------------------------------- * ------- LINK OPERATION INTO WAITING FOR LOGGING ------- * * SUBROUTINE SHORT NAME = LWL // Input Pointers: // tcConnectptr // logPartPtr * ------------------------------------------------------------------------- */ void Dblqh::linkWaitLog(Signal* signal, LogPartRecordPtr regLogPartPtr) { TcConnectionrecPtr lwlTcConnectptr; /* -------------------------------------------------- */ /* LINK ACTIVE OPERATION INTO QUEUE WAITING FOR */ /* ACCESS TO THE LOG PART. */ /* -------------------------------------------------- */ lwlTcConnectptr.i = regLogPartPtr.p->lastLogQueue; if (lwlTcConnectptr.i == RNIL) { jam(); regLogPartPtr.p->firstLogQueue = tcConnectptr.i; } else { jam(); ptrCheckGuard(lwlTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); lwlTcConnectptr.p->nextTcLogQueue = tcConnectptr.i; }//if regLogPartPtr.p->lastLogQueue = tcConnectptr.i; tcConnectptr.p->nextTcLogQueue = RNIL; if (regLogPartPtr.p->LogLqhKeyReqSent == ZFALSE) { jam(); regLogPartPtr.p->LogLqhKeyReqSent = ZTRUE; signal->theData[0] = ZLOG_LQHKEYREQ; signal->theData[1] = regLogPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if }//Dblqh::linkWaitLog() /* -------------------------------------------------------------------------- * ------- START THE NEXT OPERATION ON THIS LOG PART IF ANY ------- * ------- OPERATIONS ARE QUEUED. ------- * * SUBROUTINE SHORT NAME = LNS // Input Pointers: // tcConnectptr // logPartPtr * ------------------------------------------------------------------------- */ void Dblqh::logNextStart(Signal* signal) { LogPartRecordPtr lnsLogPartPtr; UintR tlnsStillWaiting; LogPartRecord * const regLogPartPtr = logPartPtr.p; if ((regLogPartPtr->firstLogQueue == RNIL) && (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) && (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE)) { // -------------------------------------------------------------------------- // Optimised route for the common case // -------------------------------------------------------------------------- regLogPartPtr->logPartState = LogPartRecord::IDLE; return; }//if if (regLogPartPtr->firstLogQueue != RNIL) { jam(); if (regLogPartPtr->LogLqhKeyReqSent == ZFALSE) { jam(); regLogPartPtr->LogLqhKeyReqSent = ZTRUE; signal->theData[0] = ZLOG_LQHKEYREQ; signal->theData[1] = logPartPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if } else { if (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) { jam(); regLogPartPtr->logPartState = LogPartRecord::IDLE; } else { jam(); }//if }//if if (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE) { jam(); return; } else { jam(); /* -------------------------------------------------------------------------- * A COMPLETE GCI LOG RECORD IS WAITING TO BE WRITTEN. WE GIVE THIS HIGHEST * PRIORITY AND WRITE IT IMMEDIATELY. AFTER WRITING IT WE CHECK IF ANY MORE * LOG PARTS ARE WAITING. IF NOT WE SEND A SIGNAL THAT INITIALISES THE GCP * RECORD TO WAIT UNTIL ALL COMPLETE GCI LOG RECORDS HAVE REACHED TO DISK. * -------------------------------------------------------------------------- */ writeCompletedGciLog(signal); logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; tlnsStillWaiting = ZFALSE; for (lnsLogPartPtr.i = 0; lnsLogPartPtr.i < 4; lnsLogPartPtr.i++) { jam(); ptrAss(lnsLogPartPtr, logPartRecord); if (lnsLogPartPtr.p->waitWriteGciLog == LogPartRecord::WWGL_TRUE) { jam(); tlnsStillWaiting = ZTRUE; }//if }//for if (tlnsStillWaiting == ZFALSE) { jam(); signal->theData[0] = ZINIT_GCP_REC; sendSignal(cownref, GSN_CONTINUEB, signal, 1, JBB); }//if }//if }//Dblqh::logNextStart() /* -------------------------------------------------------------------------- * ------- MOVE PAGES FROM LFO RECORD TO PAGE REFERENCE RECORD ------- * WILL ALWAYS MOVE 8 PAGES TO A PAGE REFERENCE RECORD. * * SUBROUTINE SHORT NAME = MPR * ------------------------------------------------------------------------- */ void Dblqh::moveToPageRef(Signal* signal) { LogPageRecordPtr mprLogPagePtr; PageRefRecordPtr mprPageRefPtr; UintR tmprIndex; /* -------------------------------------------------------------------------- * ------- INSERT PAGE REFERENCE RECORD ------- * * INPUT: LFO_PTR LOG FILE OPERATION RECORD * LOG_PART_PTR LOG PART RECORD * PAGE_REF_PTR THE PAGE REFERENCE RECORD TO BE INSERTED. * ------------------------------------------------------------------------- */ PageRefRecordPtr iprPageRefPtr; if ((logPartPtr.p->mmBufferSize + 8) >= ZMAX_MM_BUFFER_SIZE) { jam(); pageRefPtr.i = logPartPtr.p->firstPageRef; ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); releasePrPages(signal); removePageRef(signal); } else { jam(); logPartPtr.p->mmBufferSize = logPartPtr.p->mmBufferSize + 8; }//if seizePageRef(signal); if (logPartPtr.p->firstPageRef == RNIL) { jam(); logPartPtr.p->firstPageRef = pageRefPtr.i; } else { jam(); iprPageRefPtr.i = logPartPtr.p->lastPageRef; ptrCheckGuard(iprPageRefPtr, cpageRefFileSize, pageRefRecord); iprPageRefPtr.p->prNext = pageRefPtr.i; }//if pageRefPtr.p->prPrev = logPartPtr.p->lastPageRef; logPartPtr.p->lastPageRef = pageRefPtr.i; pageRefPtr.p->prFileNo = logFilePtr.p->fileNo; pageRefPtr.p->prPageNo = lfoPtr.p->lfoPageNo; tmprIndex = 0; mprLogPagePtr.i = lfoPtr.p->firstLfoPage; MPR_LOOP: arrGuard(tmprIndex, 8); pageRefPtr.p->pageRef[tmprIndex] = mprLogPagePtr.i; tmprIndex = tmprIndex + 1; ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord); mprLogPagePtr.i = mprLogPagePtr.p->logPageWord[ZNEXT_PAGE]; if (mprLogPagePtr.i != RNIL) { jam(); goto MPR_LOOP; }//if mprPageRefPtr.i = pageRefPtr.p->prPrev; if (mprPageRefPtr.i != RNIL) { jam(); ptrCheckGuard(mprPageRefPtr, cpageRefFileSize, pageRefRecord); mprLogPagePtr.i = mprPageRefPtr.p->pageRef[7]; ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord); mprLogPagePtr.p->logPageWord[ZNEXT_PAGE] = pageRefPtr.p->pageRef[0]; }//if }//Dblqh::moveToPageRef() /* ------------------------------------------------------------------------- */ /* ------- READ THE ATTRINFO FROM THE LOG ------- */ /* */ /* SUBROUTINE SHORT NAME = RA */ /* ------------------------------------------------------------------------- */ void Dblqh::readAttrinfo(Signal* signal) { Uint32 remainingLen = tcConnectptr.p->totSendlenAi; if (remainingLen == 0) { jam(); tcConnectptr.p->reclenAiLqhkey = 0; return; }//if Uint32 dataLen = remainingLen; if (remainingLen > 5) dataLen = 5; readLogData(signal, dataLen, &tcConnectptr.p->firstAttrinfo[0]); tcConnectptr.p->reclenAiLqhkey = dataLen; remainingLen -= dataLen; while (remainingLen > 0) { jam(); dataLen = remainingLen; if (remainingLen > 22) dataLen = 22; seizeAttrinbuf(signal); readLogData(signal, dataLen, &attrinbufptr.p->attrbuf[0]); attrinbufptr.p->attrbuf[ZINBUF_DATA_LEN] = dataLen; remainingLen -= dataLen; }//while }//Dblqh::readAttrinfo() /* ------------------------------------------------------------------------- */ /* ------- READ COMMIT LOG ------- */ /* */ /* SUBROUTINE SHORT NAME = RCL */ /* ------------------------------------------------------------------------- */ void Dblqh::readCommitLog(Signal* signal, CommitLogRecord* commitLogRecord) { Uint32 trclPageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; if ((trclPageIndex + (ZCOMMIT_LOG_SIZE - 1)) < ZPAGE_SIZE) { jam(); tcConnectptr.p->tableref = logPagePtr.p->logPageWord[trclPageIndex + 0]; tcConnectptr.p->schemaVersion = logPagePtr.p->logPageWord[trclPageIndex + 1]; tcConnectptr.p->fragmentid = logPagePtr.p->logPageWord[trclPageIndex + 2]; commitLogRecord->fileNo = logPagePtr.p->logPageWord[trclPageIndex + 3]; commitLogRecord->startPageNo = logPagePtr.p->logPageWord[trclPageIndex + 4]; commitLogRecord->startPageIndex = logPagePtr.p->logPageWord[trclPageIndex + 5]; commitLogRecord->stopPageNo = logPagePtr.p->logPageWord[trclPageIndex + 6]; tcConnectptr.p->gci = logPagePtr.p->logPageWord[trclPageIndex + 7]; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = (trclPageIndex + ZCOMMIT_LOG_SIZE) - 1; } else { jam(); tcConnectptr.p->tableref = readLogword(signal); tcConnectptr.p->schemaVersion = readLogword(signal); tcConnectptr.p->fragmentid = readLogword(signal); commitLogRecord->fileNo = readLogword(signal); commitLogRecord->startPageNo = readLogword(signal); commitLogRecord->startPageIndex = readLogword(signal); commitLogRecord->stopPageNo = readLogword(signal); tcConnectptr.p->gci = readLogword(signal); }//if tcConnectptr.p->transid[0] = logPartPtr.i + 65536; tcConnectptr.p->transid[1] = (DBLQH << 20) + (cownNodeid << 8); }//Dblqh::readCommitLog() /* ------------------------------------------------------------------------- */ /* ------- READ LOG PAGES FROM DISK IN ORDER TO EXECUTE A LOG ------- */ /* RECORD WHICH WAS NOT FOUND IN MAIN MEMORY. */ /* */ /* SUBROUTINE SHORT NAME = REL */ /* ------------------------------------------------------------------------- */ void Dblqh::readExecLog(Signal* signal) { UintR trelIndex; UintR trelI; seizeLfo(signal); initLfo(signal); trelI = logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo; arrGuard(trelI + 1, 16); lfoPtr.p->logPageArray[trelI + 1] = logPartPtr.p->execSrStartPageNo; for (trelIndex = logPartPtr.p->execSrStopPageNo; (trelIndex >= logPartPtr.p->execSrStartPageNo) && (UintR)~trelIndex; trelIndex--) { jam(); seizeLogpage(signal); arrGuard(trelI, 16); lfoPtr.p->logPageArray[trelI] = logPagePtr.i; trelI--; }//for lfoPtr.p->lfoPageNo = logPartPtr.p->execSrStartPageNo; lfoPtr.p->noPagesRw = (logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo) + 1; lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0]; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; signal->theData[3] = ZLIST_OF_MEM_PAGES; // edtjamo TR509 //ZLIST_OF_PAIRS; signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = lfoPtr.p->noPagesRw; signal->theData[6] = lfoPtr.p->logPageArray[0]; signal->theData[7] = lfoPtr.p->logPageArray[1]; signal->theData[8] = lfoPtr.p->logPageArray[2]; signal->theData[9] = lfoPtr.p->logPageArray[3]; signal->theData[10] = lfoPtr.p->logPageArray[4]; signal->theData[11] = lfoPtr.p->logPageArray[5]; signal->theData[12] = lfoPtr.p->logPageArray[6]; signal->theData[13] = lfoPtr.p->logPageArray[7]; signal->theData[14] = lfoPtr.p->logPageArray[8]; signal->theData[15] = lfoPtr.p->logPageArray[9]; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 16, JBA); }//Dblqh::readExecLog() /* ------------------------------------------------------------------------- */ /* ------- READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG ------- */ /* */ /* SUBROUTINE SHORT NAME = RES */ /* ------------------------------------------------------------------------- */ void Dblqh::readExecSrNewMbyte(Signal* signal) { logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE; logFilePtr.p->filePosition = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE; logPartPtr.p->execSrPagesRead = 0; logPartPtr.p->execSrPagesReading = 0; logPartPtr.p->execSrPagesExecuted = 0; readExecSr(signal); logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE; }//Dblqh::readExecSrNewMbyte() /* ------------------------------------------------------------------------- */ /* ------- READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG ------- */ /* */ /* SUBROUTINE SHORT NAME = RES */ /* ------------------------------------------------------------------------- */ void Dblqh::readExecSr(Signal* signal) { UintR tresPageid; UintR tresIndex; tresPageid = logFilePtr.p->filePosition; seizeLfo(signal); initLfo(signal); for (tresIndex = 7; (UintR)~tresIndex; tresIndex--) { jam(); /* ------------------------------------------------------------------------- */ /* GO BACKWARDS SINCE WE INSERT AT THE BEGINNING AND WE WANT THAT FIRST PAGE */ /* SHALL BE FIRST AND LAST PAGE LAST. */ /* ------------------------------------------------------------------------- */ seizeLogpage(signal); lfoPtr.p->logPageArray[tresIndex] = logPagePtr.i; }//for lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_SR; lfoPtr.p->lfoPageNo = tresPageid; logFilePtr.p->filePosition = logFilePtr.p->filePosition + 8; logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading + 8; lfoPtr.p->noPagesRw = 8; lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0]; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; signal->theData[3] = ZLIST_OF_MEM_PAGES; signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = 8; signal->theData[6] = lfoPtr.p->logPageArray[0]; signal->theData[7] = lfoPtr.p->logPageArray[1]; signal->theData[8] = lfoPtr.p->logPageArray[2]; signal->theData[9] = lfoPtr.p->logPageArray[3]; signal->theData[10] = lfoPtr.p->logPageArray[4]; signal->theData[11] = lfoPtr.p->logPageArray[5]; signal->theData[12] = lfoPtr.p->logPageArray[6]; signal->theData[13] = lfoPtr.p->logPageArray[7]; signal->theData[14] = tresPageid; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA); }//Dblqh::readExecSr() /* ------------------------------------------------------------------------- */ /* ------------ READ THE PRIMARY KEY FROM THE LOG ---------------- */ /* */ /* SUBROUTINE SHORT NAME = RK */ /* --------------------------------------------------------------------------*/ void Dblqh::readKey(Signal* signal) { Uint32 remainingLen = tcConnectptr.p->primKeyLen; ndbrequire(remainingLen != 0); Uint32 dataLen = remainingLen; if (remainingLen > 4) dataLen = 4; readLogData(signal, dataLen, &tcConnectptr.p->tupkeyData[0]); remainingLen -= dataLen; while (remainingLen > 0) { jam(); seizeTupkeybuf(signal); dataLen = remainingLen; if (dataLen > 4) dataLen = 4; readLogData(signal, dataLen, &databufptr.p->data[0]); remainingLen -= dataLen; }//while }//Dblqh::readKey() /* ------------------------------------------------------------------------- */ /* ------------ READ A NUMBER OF WORDS FROM LOG INTO CDATA ---------------- */ /* */ /* SUBROUTINE SHORT NAME = RLD */ /* --------------------------------------------------------------------------*/ void Dblqh::readLogData(Signal* signal, Uint32 noOfWords, Uint32* dataPtr) { ndbrequire(noOfWords < 32); Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; if ((logPos + noOfWords) >= ZPAGE_SIZE) { for (Uint32 i = 0; i < noOfWords; i++) dataPtr[i] = readLogwordExec(signal); } else { MEMCOPY_NO_WORDS(dataPtr, &logPagePtr.p->logPageWord[logPos], noOfWords); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + noOfWords; }//if }//Dblqh::readLogData() /* ------------------------------------------------------------------------- */ /* ------------ READ THE LOG HEADER OF A PREPARE LOG HEADER ---------------- */ /* */ /* SUBROUTINE SHORT NAME = RLH */ /* --------------------------------------------------------------------------*/ void Dblqh::readLogHeader(Signal* signal) { Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) { jam(); tcConnectptr.p->hashValue = logPagePtr.p->logPageWord[logPos + 2]; tcConnectptr.p->operation = logPagePtr.p->logPageWord[logPos + 3]; tcConnectptr.p->totSendlenAi = logPagePtr.p->logPageWord[logPos + 4]; tcConnectptr.p->primKeyLen = logPagePtr.p->logPageWord[logPos + 5]; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE; } else { jam(); readLogwordExec(signal); /* IGNORE PREPARE LOG RECORD TYPE */ readLogwordExec(signal); /* IGNORE LOG RECORD SIZE */ tcConnectptr.p->hashValue = readLogwordExec(signal); tcConnectptr.p->operation = readLogwordExec(signal); tcConnectptr.p->totSendlenAi = readLogwordExec(signal); tcConnectptr.p->primKeyLen = readLogwordExec(signal); }//if }//Dblqh::readLogHeader() /* ------------------------------------------------------------------------- */ /* ------- READ A WORD FROM THE LOG ------- */ /* */ /* OUTPUT: TLOG_WORD */ /* SUBROUTINE SHORT NAME = RLW */ /* ------------------------------------------------------------------------- */ Uint32 Dblqh::readLogword(Signal* signal) { Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; ndbrequire(logPos < ZPAGE_SIZE); Uint32 logWord = logPagePtr.p->logPageWord[logPos]; logPos++; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; if (logPos >= ZPAGE_SIZE) { jam(); logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; logFilePtr.p->currentLogpage = logPagePtr.i; logFilePtr.p->currentFilepage++; logPartPtr.p->execSrPagesRead--; logPartPtr.p->execSrPagesExecuted++; }//if return logWord; }//Dblqh::readLogword() /* ------------------------------------------------------------------------- */ /* ------- READ A WORD FROM THE LOG WHEN EXECUTING A LOG RECORD ------- */ /* */ /* OUTPUT: TLOG_WORD */ /* SUBROUTINE SHORT NAME = RWE */ /* ------------------------------------------------------------------------- */ Uint32 Dblqh::readLogwordExec(Signal* signal) { Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; ndbrequire(logPos < ZPAGE_SIZE); Uint32 logWord = logPagePtr.p->logPageWord[logPos]; logPos++; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; if (logPos >= ZPAGE_SIZE) { jam(); logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; if (logPagePtr.i != RNIL){ ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; } else { // Reading word at the last pos in the last page // Don't step forward to next page! jam(); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]++; } }//if return logWord; }//Dblqh::readLogwordExec() /* ------------------------------------------------------------------------- */ /* ------- READ A SINGLE PAGE FROM THE LOG ------- */ /* */ /* INPUT: TRSP_PAGE_NO */ /* SUBROUTINE SHORT NAME = RSP */ /* ------------------------------------------------------------------------- */ void Dblqh::readSinglePage(Signal* signal, Uint32 pageNo) { seizeLfo(signal); initLfo(signal); seizeLogpage(signal); lfoPtr.p->firstLfoPage = logPagePtr.i; lfoPtr.p->lfoPageNo = pageNo; lfoPtr.p->noPagesRw = 1; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; signal->theData[3] = ZLIST_OF_PAIRS; signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = 1; signal->theData[6] = logPagePtr.i; signal->theData[7] = pageNo; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); }//Dblqh::readSinglePage() /* -------------------------------------------------------------------------- * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME = RAC * ------------------------------------------------------------------------- */ void Dblqh::releaseAccList(Signal* signal) { TcConnectionrecPtr racTcNextConnectptr; TcConnectionrecPtr racTcPrevConnectptr; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); racTcPrevConnectptr.i = tcConnectptr.p->prevTc; racTcNextConnectptr.i = tcConnectptr.p->nextTc; if (tcConnectptr.p->listState != TcConnectionrec::ACC_BLOCK_LIST) { jam(); systemError(signal); }//if tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; if (racTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(racTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); racTcNextConnectptr.p->prevTc = racTcPrevConnectptr.i; }//if if (racTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(racTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); racTcPrevConnectptr.p->nextTc = tcConnectptr.p->nextTc; } else { jam(); /* --------------------------------------------------------------------- * OPERATION RECORD IS FIRST IN ACTIVE LIST * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. * --------------------------------------------------------------------- */ fragptr.p->accBlockedList = racTcNextConnectptr.i; }//if }//Dblqh::releaseAccList() /* -------------------------------------------------------------------------- * ------- REMOVE COPY FRAGMENT FROM ACTIVE COPY LIST ------- * * ------------------------------------------------------------------------- */ void Dblqh::releaseActiveCopy(Signal* signal) { /* MUST BE 8 BIT */ UintR tracFlag; UintR tracIndex; tracFlag = ZFALSE; for (tracIndex = 0; tracIndex < 4; tracIndex++) { if (tracFlag == ZFALSE) { jam(); if (cactiveCopy[tracIndex] == fragptr.i) { jam(); tracFlag = ZTRUE; }//if } else { if (tracIndex < 3) { jam(); cactiveCopy[tracIndex - 1] = cactiveCopy[tracIndex]; } else { jam(); cactiveCopy[3] = RNIL; }//if }//if }//for ndbrequire(tracFlag == ZTRUE); cnoActiveCopy--; }//Dblqh::releaseActiveCopy() /* -------------------------------------------------------------------------- * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME = RAL * ------------------------------------------------------------------------- */ void Dblqh::releaseActiveList(Signal* signal) { TcConnectionrecPtr ralTcNextConnectptr; TcConnectionrecPtr ralTcPrevConnectptr; ralTcPrevConnectptr.i = tcConnectptr.p->prevTc; ralTcNextConnectptr.i = tcConnectptr.p->nextTc; ndbrequire(tcConnectptr.p->listState == TcConnectionrec::IN_ACTIVE_LIST); tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; if (ralTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(ralTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); ralTcNextConnectptr.p->prevTc = ralTcPrevConnectptr.i; }//if if (ralTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(ralTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); ralTcPrevConnectptr.p->nextTc = tcConnectptr.p->nextTc; } else { jam(); /* ---------------------------------------------------------------------- * OPERATION RECORD IS FIRST IN ACTIVE LIST * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. * --------------------------------------------------------------------- */ fragptr.p->activeList = ralTcNextConnectptr.i; }//if }//Dblqh::releaseActiveList() /* -------------------------------------------------------------------------- * ------- RELEASE ADD FRAGMENT RECORD ------- * * ------------------------------------------------------------------------- */ void Dblqh::releaseAddfragrec(Signal* signal) { addfragptr.p->addfragStatus = AddFragRecord::FREE; addfragptr.p->nextAddfragrec = cfirstfreeAddfragrec; cfirstfreeAddfragrec = addfragptr.i; }//Dblqh::releaseAddfragrec() /* -------------------------------------------------------------------------- * ------- RELEASE FRAGMENT RECORD ------- * * ------------------------------------------------------------------------- */ void Dblqh::releaseFragrec() { fragptr.p->fragStatus = Fragrecord::FREE; fragptr.p->nextFrag = cfirstfreeFragrec; cfirstfreeFragrec = fragptr.i; }//Dblqh::releaseFragrec() /* -------------------------------------------------------------------------- * ------- RELEASE LCP LOCAL RECORD ------- * * ------------------------------------------------------------------------- */ void Dblqh::releaseLcpLoc(Signal* signal) { lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; lcpLocptr.p->nextLcpLoc = cfirstfreeLcpLoc; cfirstfreeLcpLoc = lcpLocptr.i; }//Dblqh::releaseLcpLoc() /* -------------------------------------------------------------------------- * ------- RELEASE A PAGE REFERENCE RECORD. ------- * * ------------------------------------------------------------------------- */ void Dblqh::releasePageRef(Signal* signal) { pageRefPtr.p->prNext = cfirstfreePageRef; cfirstfreePageRef = pageRefPtr.i; }//Dblqh::releasePageRef() /* -------------------------------------------------------------------------- * --- RELEASE ALL PAGES IN THE MM BUFFER AFTER EXECUTING THE LOG ON IT. ---- * * ------------------------------------------------------------------------- */ void Dblqh::releaseMmPages(Signal* signal) { RMP_LOOP: jam(); pageRefPtr.i = logPartPtr.p->firstPageRef; if (pageRefPtr.i != RNIL) { jam(); ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); releasePrPages(signal); removePageRef(signal); goto RMP_LOOP; }//if }//Dblqh::releaseMmPages() /* -------------------------------------------------------------------------- * ------- RELEASE A SET OF PAGES AFTER EXECUTING THE LOG ON IT. ------- * * ------------------------------------------------------------------------- */ void Dblqh::releasePrPages(Signal* signal) { UintR trppIndex; for (trppIndex = 0; trppIndex <= 7; trppIndex++) { jam(); logPagePtr.i = pageRefPtr.p->pageRef[trppIndex]; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); releaseLogpage(signal); }//for }//Dblqh::releasePrPages() /* -------------------------------------------------------------------------- * ------- RELEASE OPERATION FROM WAIT QUEUE LIST ON FRAGMENT ------- * * SUBROUTINE SHORT NAME : RWA * ------------------------------------------------------------------------- */ void Dblqh::releaseWaitQueue(Signal* signal) { TcConnectionrecPtr rwaTcNextConnectptr; TcConnectionrecPtr rwaTcPrevConnectptr; fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); rwaTcPrevConnectptr.i = tcConnectptr.p->prevTc; rwaTcNextConnectptr.i = tcConnectptr.p->nextTc; if (tcConnectptr.p->listState != TcConnectionrec::WAIT_QUEUE_LIST) { jam(); systemError(signal); }//if tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; if (rwaTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(rwaTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); rwaTcNextConnectptr.p->prevTc = rwaTcPrevConnectptr.i; } else { jam(); fragptr.p->lastWaitQueue = rwaTcPrevConnectptr.i; }//if if (rwaTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(rwaTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); rwaTcPrevConnectptr.p->nextTc = rwaTcNextConnectptr.i; } else { jam(); fragptr.p->firstWaitQueue = rwaTcNextConnectptr.i; }//if }//Dblqh::releaseWaitQueue() /* -------------------------------------------------------------------------- * ------- REMOVE OPERATION RECORD FROM LIST ON LOG PART OF NOT ------- * COMPLETED OPERATIONS IN THE LOG. * * SUBROUTINE SHORT NAME = RLO * ------------------------------------------------------------------------- */ void Dblqh::removeLogTcrec(Signal* signal) { TcConnectionrecPtr rloTcNextConnectptr; TcConnectionrecPtr rloTcPrevConnectptr; rloTcPrevConnectptr.i = tcConnectptr.p->prevLogTcrec; rloTcNextConnectptr.i = tcConnectptr.p->nextLogTcrec; if (rloTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i; } else { jam(); logPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i; }//if if (rloTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i; } else { jam(); logPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i; }//if }//Dblqh::removeLogTcrec() /* -------------------------------------------------------------------------- * ------- REMOVE PAGE REFERENCE RECORD FROM LIST IN THIS LOG PART ------- * * SUBROUTINE SHORT NAME = RPR * ------------------------------------------------------------------------- */ void Dblqh::removePageRef(Signal* signal) { PageRefRecordPtr rprPageRefPtr; pageRefPtr.i = logPartPtr.p->firstPageRef; if (pageRefPtr.i != RNIL) { jam(); ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); if (pageRefPtr.p->prNext == RNIL) { jam(); logPartPtr.p->lastPageRef = RNIL; logPartPtr.p->firstPageRef = RNIL; } else { jam(); logPartPtr.p->firstPageRef = pageRefPtr.p->prNext; rprPageRefPtr.i = pageRefPtr.p->prNext; ptrCheckGuard(rprPageRefPtr, cpageRefFileSize, pageRefRecord); rprPageRefPtr.p->prPrev = RNIL; }//if releasePageRef(signal); }//if }//Dblqh::removePageRef() /* ------------------------------------------------------------------------- */ /* ------- RETURN FROM EXECUTION OF LOG ------- */ /* */ /* ------------------------------------------------------------------------- */ Uint32 Dblqh::returnExecLog(Signal* signal) { tcConnectptr.p->connectState = TcConnectionrec::CONNECTED; initLogPointers(signal); logPartPtr.p->execSrExecuteIndex++; Uint32 result = checkIfExecLog(signal); if (result == ZOK) { jam(); /* ------------------------------------------------------------------------- */ /* THIS LOG RECORD WILL BE EXECUTED AGAIN TOWARDS ANOTHER NODE. */ /* ------------------------------------------------------------------------- */ logPagePtr.i = logPartPtr.p->execSrLogPage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->execSrLogPageIndex; } else { jam(); /* ------------------------------------------------------------------------- */ /* NO MORE EXECUTION OF THIS LOG RECORD. */ /* ------------------------------------------------------------------------- */ if (logPartPtr.p->logExecState == LogPartRecord::LES_EXEC_LOGREC_FROM_FILE) { jam(); /* ------------------------------------------------------------------------- */ /* THE LOG RECORD WAS READ FROM DISK. RELEASE ITS PAGES IMMEDIATELY. */ /* ------------------------------------------------------------------------- */ lfoPtr.i = logPartPtr.p->execSrLfoRec; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); releaseLfoPages(signal); releaseLfo(signal); logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; if (logPartPtr.p->execSrExecLogFile != logPartPtr.p->currentLogfile) { jam(); LogFileRecordPtr clfLogFilePtr; clfLogFilePtr.i = logPartPtr.p->execSrExecLogFile; ptrCheckGuard(clfLogFilePtr, clogFileFileSize, logFileRecord); clfLogFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG; closeFile(signal, clfLogFilePtr); result = ZCLOSE_FILE; }//if }//if logPartPtr.p->execSrExecuteIndex = 0; logPartPtr.p->execSrLogPage = RNIL; logPartPtr.p->execSrLogPageIndex = ZNIL; logPagePtr.i = logFilePtr.p->currentLogpage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->savePageIndex; }//if return result; }//Dblqh::returnExecLog() /* -------------------------------------------------------------------------- * ------- SEIZE ADD FRAGMENT RECORD ------ * * ------------------------------------------------------------------------- */ void Dblqh::seizeAddfragrec(Signal* signal) { addfragptr.i = cfirstfreeAddfragrec; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); cfirstfreeAddfragrec = addfragptr.p->nextAddfragrec; }//Dblqh::seizeAddfragrec() /* -------------------------------------------------------------------------- * ------- SEIZE FRAGMENT RECORD ------- * * ------------------------------------------------------------------------- */ void Dblqh::seizeFragmentrec(Signal* signal) { fragptr.i = cfirstfreeFragrec; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); cfirstfreeFragrec = fragptr.p->nextFrag; fragptr.p->nextFrag = RNIL; }//Dblqh::seizeFragmentrec() /* ------------------------------------------------------------------------- */ /* ------- SEIZE A PAGE REFERENCE RECORD. ------- */ /* */ /* ------------------------------------------------------------------------- */ void Dblqh::seizePageRef(Signal* signal) { pageRefPtr.i = cfirstfreePageRef; ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); cfirstfreePageRef = pageRefPtr.p->prNext; pageRefPtr.p->prNext = RNIL; }//Dblqh::seizePageRef() /* -------------------------------------------------------------------------- * ------- SEND ABORTED ------- * * ------------------------------------------------------------------------- */ void Dblqh::sendAborted(Signal* signal) { UintR TlastInd; if (tcConnectptr.p->nextReplica == ZNIL) { TlastInd = ZTRUE; } else { TlastInd = ZFALSE; }//if signal->theData[0] = tcConnectptr.p->tcOprec; signal->theData[1] = tcConnectptr.p->transid[0]; signal->theData[2] = tcConnectptr.p->transid[1]; signal->theData[3] = cownNodeid; signal->theData[4] = TlastInd; sendSignal(tcConnectptr.p->tcBlockref, GSN_ABORTED, signal, 5, JBB); return; }//Dblqh::sendAborted() /* -------------------------------------------------------------------------- * ------- SEND LQH_TRANSCONF ------- * * ------------------------------------------------------------------------- */ void Dblqh::sendLqhTransconf(Signal* signal, LqhTransConf::OperationStatus stat) { tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); Uint32 reqInfo = 0; LqhTransConf::setReplicaType(reqInfo, tcConnectptr.p->replicaType); LqhTransConf::setReplicaNo(reqInfo, tcConnectptr.p->seqNoReplica); LqhTransConf::setLastReplicaNo(reqInfo, tcConnectptr.p->lastReplicaNo); LqhTransConf::setSimpleFlag(reqInfo, tcConnectptr.p->opSimple); LqhTransConf::setDirtyFlag(reqInfo, tcConnectptr.p->dirtyOp); LqhTransConf::setOperation(reqInfo, tcConnectptr.p->operation); LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0]; lqhTransConf->tcRef = tcNodeFailptr.p->newTcRef; lqhTransConf->lqhNodeId = cownNodeid; lqhTransConf->operationStatus = stat; lqhTransConf->lqhConnectPtr = tcConnectptr.i; lqhTransConf->transId1 = tcConnectptr.p->transid[0]; lqhTransConf->transId2 = tcConnectptr.p->transid[1]; lqhTransConf->oldTcOpRec = tcConnectptr.p->tcOprec; lqhTransConf->requestInfo = reqInfo; lqhTransConf->gci = tcConnectptr.p->gci; lqhTransConf->nextNodeId1 = tcConnectptr.p->nextReplica; lqhTransConf->nextNodeId2 = tcConnectptr.p->nodeAfterNext[0]; lqhTransConf->nextNodeId3 = tcConnectptr.p->nodeAfterNext[1]; lqhTransConf->apiRef = tcConnectptr.p->applRef; lqhTransConf->apiOpRec = tcConnectptr.p->applOprec; lqhTransConf->tableId = tcConnectptr.p->tableref; sendSignal(tcNodeFailptr.p->newTcBlockref, GSN_LQH_TRANSCONF, signal, LqhTransConf::SignalLength, JBB); tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; signal->theData[0] = ZLQH_TRANS_NEXT; signal->theData[1] = tcNodeFailptr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//Dblqh::sendLqhTransconf() /* -------------------------------------------------------------------------- * ------- START ANOTHER PHASE OF LOG EXECUTION ------- * RESET THE VARIABLES NEEDED BY THIS PROCESS AND SEND THE START SIGNAL * * ------------------------------------------------------------------------- */ void Dblqh::startExecSr(Signal* signal) { cnoFragmentsExecSr = 0; signal->theData[0] = cfirstCompletedFragSr; signal->theData[1] = RNIL; sendSignal(cownref, GSN_START_EXEC_SR, signal, 2, JBB); }//Dblqh::startExecSr() /* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ * ¤¤¤¤¤¤¤ LOG MODULE ¤¤¤¤¤¤¤ * ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */ /* -------------------------------------------------------------------------- * ------- STEP FORWARD IN FRAGMENT LOG DURING LOG EXECUTION ------- * * ------------------------------------------------------------------------- */ void Dblqh::stepAhead(Signal* signal, Uint32 stepAheadWords) { UintR tsaPos; tsaPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; while ((stepAheadWords + tsaPos) >= ZPAGE_SIZE) { jam(); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_SIZE; stepAheadWords = stepAheadWords - (ZPAGE_SIZE - tsaPos); logFilePtr.p->currentLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logFilePtr.p->currentFilepage++; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; logPartPtr.p->execSrPagesRead--; logPartPtr.p->execSrPagesExecuted++; tsaPos = ZPAGE_HEADER_SIZE; }//while logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = stepAheadWords + tsaPos; }//Dblqh::stepAhead() /* -------------------------------------------------------------------------- * ------- WRITE A ABORT LOG RECORD ------- * * SUBROUTINE SHORT NAME: WAL * ------------------------------------------------------------------------- */ void Dblqh::writeAbortLog(Signal* signal) { if ((ZABORT_LOG_SIZE + ZNEXT_LOG_SIZE) > logFilePtr.p->remainingWordsInMbyte) { jam(); changeMbyte(signal); }//if logFilePtr.p->remainingWordsInMbyte = logFilePtr.p->remainingWordsInMbyte - ZABORT_LOG_SIZE; writeLogWord(signal, ZABORT_TYPE); writeLogWord(signal, tcConnectptr.p->transid[0]); writeLogWord(signal, tcConnectptr.p->transid[1]); }//Dblqh::writeAbortLog() /* -------------------------------------------------------------------------- * ------- WRITE A COMMIT LOG RECORD ------- * * SUBROUTINE SHORT NAME: WCL * ------------------------------------------------------------------------- */ void Dblqh::writeCommitLog(Signal* signal, LogPartRecordPtr regLogPartPtr) { LogFileRecordPtr regLogFilePtr; LogPageRecordPtr regLogPagePtr; TcConnectionrec * const regTcPtr = tcConnectptr.p; regLogFilePtr.i = regLogPartPtr.p->currentLogfile; ptrCheckGuard(regLogFilePtr, clogFileFileSize, logFileRecord); regLogPagePtr.i = regLogFilePtr.p->currentLogpage; Uint32 twclTmp = regLogFilePtr.p->remainingWordsInMbyte; ptrCheckGuard(regLogPagePtr, clogPageFileSize, logPageRecord); logPartPtr = regLogPartPtr; logFilePtr = regLogFilePtr; logPagePtr = regLogPagePtr; if ((ZCOMMIT_LOG_SIZE + ZNEXT_LOG_SIZE) > twclTmp) { jam(); changeMbyte(signal); twclTmp = logFilePtr.p->remainingWordsInMbyte; }//if Uint32 twclLogPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; Uint32 tableId = regTcPtr->tableref; Uint32 schemaVersion = regTcPtr->schemaVersion; Uint32 fragId = regTcPtr->fragmentid; Uint32 fileNo = regTcPtr->logStartFileNo; Uint32 startPageNo = regTcPtr->logStartPageNo; Uint32 pageIndex = regTcPtr->logStartPageIndex; Uint32 stopPageNo = regTcPtr->logStopPageNo; Uint32 gci = regTcPtr->gci; logFilePtr.p->remainingWordsInMbyte = twclTmp - ZCOMMIT_LOG_SIZE; if ((twclLogPos + ZCOMMIT_LOG_SIZE) >= ZPAGE_SIZE) { writeLogWord(signal, ZCOMMIT_TYPE); writeLogWord(signal, tableId); writeLogWord(signal, schemaVersion); writeLogWord(signal, fragId); writeLogWord(signal, fileNo); writeLogWord(signal, startPageNo); writeLogWord(signal, pageIndex); writeLogWord(signal, stopPageNo); writeLogWord(signal, gci); } else { Uint32* dataPtr = &logPagePtr.p->logPageWord[twclLogPos]; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = twclLogPos + ZCOMMIT_LOG_SIZE; dataPtr[0] = ZCOMMIT_TYPE; dataPtr[1] = tableId; dataPtr[2] = schemaVersion; dataPtr[3] = fragId; dataPtr[4] = fileNo; dataPtr[5] = startPageNo; dataPtr[6] = pageIndex; dataPtr[7] = stopPageNo; dataPtr[8] = gci; }//if TcConnectionrecPtr rloTcNextConnectptr; TcConnectionrecPtr rloTcPrevConnectptr; rloTcPrevConnectptr.i = regTcPtr->prevLogTcrec; rloTcNextConnectptr.i = regTcPtr->nextLogTcrec; if (rloTcNextConnectptr.i != RNIL) { jam(); ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i; } else { regLogPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i; }//if if (rloTcPrevConnectptr.i != RNIL) { jam(); ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i; } else { regLogPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i; }//if }//Dblqh::writeCommitLog() /* -------------------------------------------------------------------------- * ------- WRITE A COMPLETED GCI LOG RECORD ------- * * SUBROUTINE SHORT NAME: WCG // Input Pointers: // logFilePtr // logPartPtr * ------------------------------------------------------------------------- */ void Dblqh::writeCompletedGciLog(Signal* signal) { if ((ZCOMPLETED_GCI_LOG_SIZE + ZNEXT_LOG_SIZE) > logFilePtr.p->remainingWordsInMbyte) { jam(); changeMbyte(signal); }//if logFilePtr.p->remainingWordsInMbyte = logFilePtr.p->remainingWordsInMbyte - ZCOMPLETED_GCI_LOG_SIZE; writeLogWord(signal, ZCOMPLETED_GCI_TYPE); writeLogWord(signal, cnewestCompletedGci); logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; }//Dblqh::writeCompletedGciLog() /* -------------------------------------------------------------------------- * ------- WRITE A DIRTY PAGE DURING LOG EXECUTION ------- * * SUBROUTINE SHORT NAME: WD * ------------------------------------------------------------------------- */ void Dblqh::writeDirty(Signal* signal) { logPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); seizeLfo(signal); initLfo(signal); lfoPtr.p->lfoPageNo = logPartPtr.p->prevFilepage; lfoPtr.p->noPagesRw = 1; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_DIRTY; lfoPtr.p->firstLfoPage = logPagePtr.i; signal->theData[0] = logFilePtr.p->fileRef; signal->theData[1] = cownref; signal->theData[2] = lfoPtr.i; signal->theData[3] = ZLIST_OF_PAIRS_SYNCH; signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; signal->theData[5] = 1; signal->theData[6] = logPagePtr.i; signal->theData[7] = logPartPtr.p->prevFilepage; sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); }//Dblqh::writeDirty() /* -------------------------------------------------------------------------- * ------- WRITE A WORD INTO THE LOG, CHECK FOR NEW PAGE ------- * * SUBROUTINE SHORT NAME: WLW * ------------------------------------------------------------------------- */ void Dblqh::writeLogWord(Signal* signal, Uint32 data) { Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; ndbrequire(logPos < ZPAGE_SIZE); logPagePtr.p->logPageWord[logPos] = data; logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + 1; if ((logPos + 1) == ZPAGE_SIZE) { jam(); completedLogPage(signal, ZNORMAL); seizeLogpage(signal); initLogpage(signal); logFilePtr.p->currentLogpage = logPagePtr.i; logFilePtr.p->currentFilepage++; }//if }//Dblqh::writeLogWord() /* -------------------------------------------------------------------------- * ------- WRITE A NEXT LOG RECORD AND CHANGE TO NEXT MBYTE ------- * * SUBROUTINE SHORT NAME: WNL // Input Pointers: // logFilePtr(Redefines) // logPagePtr (Redefines) // logPartPtr * ------------------------------------------------------------------------- */ void Dblqh::writeNextLog(Signal* signal) { LogFileRecordPtr wnlNextLogFilePtr; UintR twnlNextFileNo; UintR twnlNewMbyte; UintR twnlRemWords; UintR twnlNextMbyte; /* -------------------------------------------------- */ /* CALCULATE THE NEW NUMBER OF REMAINING WORDS */ /* AS 128*2036 WHERE 128 * 8 KBYTE = 1 MBYTE */ /* AND 2036 IS THE NUMBER OF WORDS IN A PAGE */ /* THAT IS USED FOR LOG INFORMATION. */ /* -------------------------------------------------- */ twnlRemWords = ZPAGE_SIZE - ZPAGE_HEADER_SIZE; twnlRemWords = twnlRemWords * ZPAGES_IN_MBYTE; wnlNextLogFilePtr.i = logFilePtr.p->nextLogFile; ptrCheckGuard(wnlNextLogFilePtr, clogFileFileSize, logFileRecord); /* -------------------------------------------------- */ /* WRITE THE NEXT LOG RECORD. */ /* -------------------------------------------------- */ ndbrequire(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] < ZPAGE_SIZE); logPagePtr.p->logPageWord[logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]] = ZNEXT_MBYTE_TYPE; if (logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)) { jam(); /* -------------------------------------------------- */ /* CALCULATE THE NEW REMAINING WORDS WHEN */ /* CHANGING LOG FILE IS PERFORMED */ /* -------------------------------------------------- */ twnlRemWords = twnlRemWords - (ZPAGE_SIZE - ZPAGE_HEADER_SIZE); /* -------------------------------------------------- */ /* ENSURE THAT THE LOG PAGES ARE WRITTEN AFTER */ /* WE HAVE CHANGED MBYTE. */ /* -------------------------------------------------- */ /* ENSURE LAST PAGE IN PREVIOUS MBYTE IS */ /* WRITTEN AND THAT THE STATE OF THE WRITE IS */ /* PROPERLY SET. */ /* -------------------------------------------------- */ /* WE HAVE TO CHANGE LOG FILE */ /* -------------------------------------------------- */ completedLogPage(signal, ZLAST_WRITE_IN_FILE); if (wnlNextLogFilePtr.p->fileNo == 0) { jam(); /* -------------------------------------------------- */ /* WE HAVE FINALISED A LOG LAP, START FROM LOG */ /* FILE 0 AGAIN */ /* -------------------------------------------------- */ logPartPtr.p->logLap++; }//if logPartPtr.p->currentLogfile = wnlNextLogFilePtr.i; logFilePtr.i = wnlNextLogFilePtr.i; logFilePtr.p = wnlNextLogFilePtr.p; twnlNewMbyte = 0; } else { jam(); /* -------------------------------------------------- */ /* INCREMENT THE CURRENT MBYTE */ /* SET PAGE INDEX TO PAGE HEADER SIZE */ /* -------------------------------------------------- */ completedLogPage(signal, ZENFORCE_WRITE); twnlNewMbyte = logFilePtr.p->currentMbyte + 1; }//if /* -------------------------------------------------- */ /* CHANGE TO NEW LOG FILE IF NECESSARY */ /* UPDATE THE FILE POSITION TO THE NEW MBYTE */ /* FOUND IN PAGE PART OF TNEXT_LOG_PTR */ /* ALLOCATE AND INITIATE A NEW PAGE SINCE WE */ /* HAVE SENT THE PREVIOUS PAGE TO DISK. */ /* SET THE NEW NUMBER OF REMAINING WORDS IN THE */ /* NEW MBYTE ALLOCATED. */ /* -------------------------------------------------- */ logFilePtr.p->currentMbyte = twnlNewMbyte; logFilePtr.p->filePosition = twnlNewMbyte * ZPAGES_IN_MBYTE; logFilePtr.p->currentFilepage = twnlNewMbyte * ZPAGES_IN_MBYTE; logFilePtr.p->remainingWordsInMbyte = twnlRemWords; seizeLogpage(signal); if (logFilePtr.p->currentMbyte == 0) { jam(); logFilePtr.p->lastPageWritten = 0; if (logFilePtr.p->fileNo == 0) { jam(); releaseLogpage(signal); logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); }//if }//if initLogpage(signal); logFilePtr.p->currentLogpage = logPagePtr.i; if (logFilePtr.p->currentMbyte == 0) { jam(); /* -------------------------------------------------- */ /* THIS IS A NEW FILE, WRITE THE FILE DESCRIPTOR*/ /* ALSO OPEN THE NEXT LOG FILE TO ENSURE THAT */ /* THIS FILE IS OPEN WHEN ITS TURN COMES. */ /* -------------------------------------------------- */ writeFileHeaderOpen(signal, ZNORMAL); openNextLogfile(signal); logFilePtr.p->fileChangeState = LogFileRecord::BOTH_WRITES_ONGOING; }//if if (logFilePtr.p->fileNo == logPartPtr.p->logTailFileNo) { if (logFilePtr.p->currentMbyte == logPartPtr.p->logTailMbyte) { jam(); /* -------------------------------------------------- */ /* THE HEAD AND TAIL HAS MET. THIS SHOULD NEVER */ /* OCCUR. CAN HAPPEN IF THE LOCAL CHECKPOINTS */ /* TAKE FAR TOO LONG TIME. SO TIMING PROBLEMS */ /* CAN INVOKE THIS SYSTEM CRASH. HOWEVER ONLY */ /* VERY SERIOUS TIMING PROBLEMS. */ /* -------------------------------------------------- */ systemError(signal); }//if }//if if (logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)) { jam(); twnlNextMbyte = 0; if (logFilePtr.p->fileChangeState != LogFileRecord::NOT_ONGOING) { jam(); logPartPtr.p->logPartState = LogPartRecord::FILE_CHANGE_PROBLEM; }//if twnlNextFileNo = wnlNextLogFilePtr.p->fileNo; } else { jam(); twnlNextMbyte = logFilePtr.p->currentMbyte + 1; twnlNextFileNo = logFilePtr.p->fileNo; }//if if (twnlNextFileNo == logPartPtr.p->logTailFileNo) { if (logPartPtr.p->logTailMbyte == twnlNextMbyte) { jam(); /* -------------------------------------------------- */ /* THE NEXT MBYTE WILL BE THE TAIL. WE MUST */ /* STOP LOGGING NEW OPERATIONS. THIS OPERATION */ /* ALLOWED TO PASS. ALSO COMMIT, NEXT, COMPLETED*/ /* GCI, ABORT AND FRAGMENT SPLIT IS ALLOWED. */ /* OPERATIONS ARE ALLOWED AGAIN WHEN THE TAIL */ /* IS MOVED FORWARD AS A RESULT OF A START_LCP */ /* _ROUND SIGNAL ARRIVING FROM DBDIH. */ /* -------------------------------------------------- */ logPartPtr.p->logPartState = LogPartRecord::TAIL_PROBLEM; }//if }//if }//Dblqh::writeNextLog() void Dblqh::execDUMP_STATE_ORD(Signal* signal) { DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0]; if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersSize){ infoEvent("LQH: m_commitAckMarkerPool: %d free size: %d", m_commitAckMarkerPool.getNoOfFree(), m_commitAckMarkerPool.getSize()); } if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersDump){ infoEvent("LQH: 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)" " ApiRef: 0x%x apiOprec: 0x%x TcNodeId: %d", iter.curr.i, iter.curr.p->transid1, iter.curr.p->transid2, iter.curr.p->apiRef, iter.curr.p->apiOprec, iter.curr.p->tcNodeId); } } // Dump info about number of log pages if(dumpState->args[0] == DumpStateOrd::LqhDumpNoLogPages){ infoEvent("LQH: Log pages : %d Free: %d", clogPageFileSize, cnoOfLogPages); } // Dump all defined tables that LQH knowns about if(dumpState->args[0] == DumpStateOrd::LqhDumpAllDefinedTabs){ for(Uint32 i = 0; i<ctabrecFileSize; i++){ TablerecPtr tabPtr; tabPtr.i = i; ptrAss(tabPtr, tablerec); if(tabPtr.p->tableStatus != Tablerec::NOT_DEFINED){ infoEvent("Table %d Status: %d Usage: %d", i, tabPtr.p->tableStatus, tabPtr.p->usageCount); } } return; } // Dump all ScanRecords if (dumpState->args[0] == DumpStateOrd::LqhDumpAllScanRec){ Uint32 recordNo = 0; if (signal->length() == 1) infoEvent("LQH: Dump all ScanRecords - size: %d", cscanrecFileSize); else if (signal->length() == 2) recordNo = dumpState->args[1]; else return; dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); if (recordNo < cscanrecFileSize-1){ dumpState->args[0] = DumpStateOrd::LqhDumpAllScanRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } return; } // Dump all active ScanRecords if (dumpState->args[0] == DumpStateOrd::LqhDumpAllActiveScanRec){ Uint32 recordNo = 0; if (signal->length() == 1) infoEvent("LQH: Dump active ScanRecord - size: %d", cscanrecFileSize); else if (signal->length() == 2) recordNo = dumpState->args[1]; else return; ScanRecordPtr sp; sp.i = recordNo; c_scanRecordPool.getPtr(scanptr); if (sp.p->scanState != ScanRecord::SCAN_FREE){ dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec; dumpState->args[1] = recordNo; execDUMP_STATE_ORD(signal); } if (recordNo < cscanrecFileSize-1){ dumpState->args[0] = DumpStateOrd::LqhDumpAllActiveScanRec; dumpState->args[1] = recordNo+1; sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); } return; } if(dumpState->args[0] == DumpStateOrd::LqhDumpOneScanRec){ Uint32 recordNo = RNIL; if (signal->length() == 2) recordNo = dumpState->args[1]; else return; if (recordNo >= cscanrecFileSize) return; ScanRecordPtr sp; sp.i = recordNo; c_scanRecordPool.getPtr(sp); infoEvent("Dblqh::ScanRecord[%d]: state=%d, type=%d, " "complStatus=%d, scanNodeId=%d", sp.i, sp.p->scanState, sp.p->scanType, sp.p->scanCompletedStatus, sp.p->scanNodeId); infoEvent(" apiBref=0x%x, scanAccPtr=%d", sp.p->scanApiBlockref, sp.p->scanAccPtr); infoEvent(" copyptr=%d, ailen=%d, complOps=%d, concurrOps=%d", sp.p->copyPtr, sp.p->scanAiLength, sp.p->m_curr_batch_size_rows, sp.p->m_max_batch_size_rows); infoEvent(" errCnt=%d, localFid=%d, schV=%d", sp.p->scanErrorCounter, sp.p->scanLocalFragid, sp.p->scanSchemaVersion); infoEvent(" stpid=%d, flag=%d, lhold=%d, lmode=%d, num=%d", sp.p->scanStoredProcId, sp.p->scanFlag, sp.p->scanLockHold, sp.p->scanLockMode, sp.p->scanNumber); infoEvent(" relCount=%d, TCwait=%d, TCRec=%d, KIflag=%d", sp.p->scanReleaseCounter, sp.p->scanTcWaiting, sp.p->scanTcrec, sp.p->scanKeyinfoFlag); return; } if(dumpState->args[0] == DumpStateOrd::LqhDumpLcpState){ infoEvent("== LQH LCP STATE =="); infoEvent(" clcpCompletedState=%d, c_lcpId=%d, cnoOfFragsCheckpointed=%d", clcpCompletedState, c_lcpId, cnoOfFragsCheckpointed); LcpRecordPtr TlcpPtr; // Print information about the current local checkpoint TlcpPtr.i = 0; ptrAss(TlcpPtr, lcpRecord); infoEvent(" lcpState=%d firstLcpLocTup=%d firstLcpLocAcc=%d", TlcpPtr.p->lcpState, TlcpPtr.p->firstLcpLocTup, TlcpPtr.p->firstLcpLocAcc); infoEvent(" lcpAccptr=%d lastFragmentFlag=%d", TlcpPtr.p->lcpAccptr, TlcpPtr.p->lastFragmentFlag); infoEvent("currentFragment.fragPtrI=%d", TlcpPtr.p->currentFragment.fragPtrI); infoEvent("currentFragment.lcpFragOrd.tableId=%d", TlcpPtr.p->currentFragment.lcpFragOrd.tableId); infoEvent(" lcpQueued=%d reportEmpty=%d", TlcpPtr.p->lcpQueued, TlcpPtr.p->reportEmpty); char buf[8*_NDB_NODE_BITMASK_SIZE+1]; infoEvent(" m_EMPTY_LCP_REQ=%d", TlcpPtr.p->m_EMPTY_LCP_REQ.getText(buf)); return; } }//Dblqh::execDUMP_STATE_ORD() void Dblqh::execSET_VAR_REQ(Signal* signal) { #if 0 SetVarReq* const setVarReq = (SetVarReq*)&signal->theData[0]; ConfigParamId var = setVarReq->variable(); switch (var) { case NoOfConcurrentCheckpointsAfterRestart: sendSignal(CMVMI_REF, GSN_SET_VAR_CONF, signal, 1, JBB); break; case NoOfConcurrentCheckpointsDuringRestart: // Valid only during start so value not set. sendSignal(CMVMI_REF, GSN_SET_VAR_CONF, signal, 1, JBB); break; default: sendSignal(CMVMI_REF, GSN_SET_VAR_REF, signal, 1, JBB); } // switch #endif }//execSET_VAR_REQ() /* **************************************************************** */ /* ---------------------------------------------------------------- */ /* ---------------------- TRIGGER HANDLING ------------------------ */ /* ---------------------------------------------------------------- */ /* */ /* All trigger signals from TRIX are forwarded top TUP */ /* ---------------------------------------------------------------- */ /* **************************************************************** */ // Trigger signals void Dblqh::execCREATE_TRIG_REQ(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference tupref = calcTupBlockRef(myNodeId); sendSignal(tupref, GSN_CREATE_TRIG_REQ, signal, CreateTrigReq::SignalLength, JBB); } void Dblqh::execCREATE_TRIG_CONF(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference dictref = calcDictBlockRef(myNodeId); sendSignal(dictref, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB); } void Dblqh::execCREATE_TRIG_REF(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference dictref = calcDictBlockRef(myNodeId); sendSignal(dictref, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB); } void Dblqh::execDROP_TRIG_REQ(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference tupref = calcTupBlockRef(myNodeId); sendSignal(tupref, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); } void Dblqh::execDROP_TRIG_CONF(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference dictref = calcDictBlockRef(myNodeId); sendSignal(dictref, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB); } void Dblqh::execDROP_TRIG_REF(Signal* signal) { jamEntry(); NodeId myNodeId = getOwnNodeId(); BlockReference dictref = calcDictBlockRef(myNodeId); sendSignal(dictref, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB); } Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){ Uint32 checkSum = 37; #ifdef VM_TRACE for (Uint32 i = (ZPOS_CHECKSUM+1); i<ZPAGE_SIZE; i++) checkSum = logP.p->logPageWord[i] ^ checkSum; #endif return checkSum; }