/* 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; #else #define DEBUG(x) #endif 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_SCANS_PER_FRAG; 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 < NO_OF_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; 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; 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 = (NO_OF_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->scanAccOpPtr[16]; //TscanPtr.p->scanApiOpPtr[16]; //TscanPtr.p->scanOpLength[16]; //TscanPtr.p->scanLocalref[2]; ndbout << " copyPtr="<<TscanPtr.p->copyPtr << " scanAccPtr="<<TscanPtr.p->scanAccPtr << " scanAiLength="<<TscanPtr.p->scanAiLength << endl; ndbout << " scanCompletedOperations="<< TscanPtr.p->scanCompletedOperations << " scanConcurrentOperations="<< TscanPtr.p->scanConcurrentOperations << " 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); } /* -------------------------------------------------------------------------- */ /* ------- 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() /* ************>> */ /* 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; if (regTcPtr->transactionState != TcConnectionrec::WAIT_TUPKEYINFO) { 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(); terrorCode = errorCode; abortErrorLab(signal); return; }//if 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 = cfirstfreeAttrinbuf; tmpAttrinbufptr.i = tcConnectptr.p->lastAttrinbuf; ptrCheckGuard(regAttrinbufptr, tattrinbufFileSize, regAttrbuf); Uint32 nextFirst = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; 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; cfirstfreeAttrinbuf = nextFirst; 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 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; 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 */ /* -------------------------------------------------------------------------- */ 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); ndbassert(scanptr.i != RNIL); } if (scanptr.i == RNIL) { jam(); releaseActiveFrag(signal); takeOverErrorLab(signal); return; }//if Uint32 accOpPtr = scanptr.p->scanAccOpPtr[ttcScanOp]; 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); }//if EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACCKEYREQ, signal, 7 + regTcPtr->primKeyLen); if (signal->theData[0] < RNIL) { signal->theData[0] = tcConnectptr.i; execACCKEYCONF(signal); return; } else if (signal->theData[0] == RNIL) { ; } else { ndbrequire(signal->theData[0] == (UintR)-1); signal->theData[0] = tcConnectptr.i; execACCKEYREF(signal); }//if return; }//Dblqh::prepareContinueAfterBlockedLab() /* ========================================================================== */ /* ======= SEND KEYINFO TO ACC ======= */ /* */ /* ========================================================================== */ void Dblqh::sendKeyinfoAcc(Signal* signal) { UintR Ti = 11; 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(); ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); Tmpbuf = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; regAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = cfirstfreeAttrinbuf; cfirstfreeAttrinbuf = regAttrinbufptr.i; regAttrinbufptr.i = Tmpbuf; }//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]; if (ERROR_INSERTED(5003)) { systemErrorLab(signal); } if (ERROR_INSERTED(5015)) { CLEAR_ERROR_INSERT_VALUE; sendSignalWithDelay(cownref, GSN_ABORT, signal, 2000, 4); return; }//if if (findTransaction(transid1, transid2, tcOprec) != ZOK) { jam(); /* ------------------------------------------------------------------------- */ // 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; 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 */ ndbrequire (tcPtr->seqNoReplica == 0 || (errCode != ZTUPLE_ALREADY_EXIST && errCode != ZNO_TUPLE_FOUND) || (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 LOCAL CHECKPOINT. */ /* ------------------------------------------------------------------------- */ releaseWaitQueue(signal); 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(); 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]; NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0]; TnoOfNodes = nodeFail->noOfNodes; UintR index = 0; for (Uint32 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 (Uint32 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(Uint32 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("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 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; } closeScanRequestLab(signal); return; }//if fragptr.i = tcConnectptr.p->fragmentptr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); /* -------------------------------------------------------------------- * 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->scanCompletedOperations > 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 // Update timer on tcConnectRecord tcConnectptr.p->tcTimer = cLqhTimeOutCount; initScanAccOp(signal); scanptr.p->scanCompletedOperations = 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; ndbrequire((scanptr.p->scanReleaseCounter -1) < MAX_PARALLEL_OP_PER_SCAN); signal->theData[1] = scanptr.p->scanAccOpPtr[scanptr.p->scanReleaseCounter -1]; 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->scanCompletedOperations > 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->scanCompletedOperations = 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->scanCompletedOperations) { if ((scanptr.p->scanErrorCounter > 0) || (scanptr.p->scanCompletedStatus == ZTRUE)) { jam(); closeScanLab(signal); } else if ((scanptr.p->scanConcurrentOperations == scanptr.p->scanCompletedOperations) && 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->scanCompletedOperations) { 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 scanConcurrentOperations 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() /* ------------------------------------------------------------------------- * SCAN_FRAGREQ: Request to start scanning the specified fragment of a table. * ------------------------------------------------------------------------- */ void Dblqh::execSCAN_FRAGREQ(Signal* signal) { const ScanFragReq * const scanFragReq = (ScanFragReq *)&signal->theData[0]; ScanFragRef * ref; const Uint32 transid1 = scanFragReq->transId1; const Uint32 transid2 = scanFragReq->transId2; Uint32 errorCode; Uint32 senderData; Uint32 hashIndex; TcConnectionrecPtr nextHashptr; jamEntry(); const Uint32 reqinfo = scanFragReq->requestInfo; const Uint32 fragId = scanFragReq->fragmentNo; tabptr.i = scanFragReq->tableId; const Uint32 scanConcurrentOperations = ScanFragReq::getConcurrency(reqinfo); 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(scanConcurrentOperations <= MAX_PARALLEL_OP_PER_SCAN); ndbrequire(scanConcurrentOperations != 0); 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 + scanConcurrentOperations) > cmaxAccOps) { jam(); errorCode = ScanFragRef::ZSCAN_BOOK_ACC_OP_ERROR; goto error_handler; }//if ndbrequire(c_scanRecordPool.seize(scanptr)); initScanTc(signal, transid1, transid2, fragId, ZNIL); errorCode = initScanrec(scanFragReq); if (errorCode != ZOK) { jam(); goto error_handler2; }//if cscanNoFreeRec--; cbookedAccOps += scanConcurrentOperations; 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) { if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { scanptr.i = tcConnectptr.p->tcScanRec; c_scanRecordPool.getPtr(scanptr); 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; AttrbufPtr regAttrinbufptr; regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf; Uint32 boundAiLength = 0; if (scanptr.p->rangeScan) { jam(); // bound info length is in first of the 5 header words ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); boundAiLength = regAttrinbufptr.p->attrbuf[0]; TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend(); req->errorCode = RNIL; req->tuxScanPtrI = scanptr.p->scanAccPtr; req->boundAiLength = boundAiLength; Uint32* out = (Uint32*)req + TuxBoundInfo::SignalLength; Uint32 sz = 0; while (sz < boundAiLength) { jam(); ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; MEMCOPY_NO_WORDS(&out[sz], ®Attrinbufptr.p->attrbuf[0], dataLen); sz += dataLen; regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); } ndbrequire(sz == boundAiLength); EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO, signal, TuxBoundInfo::SignalLength + boundAiLength); 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; ndbrequire(boundAiLength <= scanptr.p->scanAiLength); signal->theData[4] = scanptr.p->scanAiLength - boundAiLength; sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); signal->theData[0] = tcConnectptr.p->tupConnectrec; 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; initScanAccOp(signal); 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->scanCompletedOperations > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->scanCompletedOperations > 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->scanCompletedOperations > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->scanCompletedOperations > 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 ndbrequire(scanptr.p->scanCompletedOperations < MAX_PARALLEL_OP_PER_SCAN); scanptr.p->scanAccOpPtr[scanptr.p->scanCompletedOperations] = nextScanConf->accOperationPtr; 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 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->scanCompletedOperations > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if closeScanLab(signal); return; }//if 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 } { 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; ndbrequire(scanptr.p->scanCompletedOperations < MAX_PARALLEL_OP_PER_SCAN); tupKeyReq->opRef = scanptr.p->scanApiOpPtr[scanptr.p->scanCompletedOperations]; 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); } }//Dblqh::nextScanConfLoopLab() /* ------------------------------------------------------------------------- * 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) { UintR tdata3; UintR tdata4; UintR tdata5; tdata3 = signal->theData[2]; tdata4 = signal->theData[3]; tdata5 = signal->theData[4]; 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->scanCompletedOperations > 0)) { jam(); scanptr.p->scanReleaseCounter = 1; scanReleaseLocksLab(signal); return; }//if jam(); closeScanLab(signal); return; }//if if (scanptr.p->scanKeyinfoFlag) { jam(); DatabufPtr TdataBuf; TdataBuf.i = tcConnectptr.p->firstTupkeybuf; const Uint32 keyLen = tcConnectptr.p->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)); KeyInfo20 * keyInfo = (KeyInfo20*)&signal->theData[0]; for(Uint32 i = 0; i < keyLen; i += 4){ ptrCheckGuard(TdataBuf, dataBufSz, databuf); keyInfo->keyData[i + 0] = TdataBuf.p->data[0]; keyInfo->keyData[i + 1] = TdataBuf.p->data[1]; keyInfo->keyData[i + 2] = TdataBuf.p->data[2]; keyInfo->keyData[i + 3] = TdataBuf.p->data[3]; TdataBuf.i = TdataBuf.p->nextDatabuf; } sendKeyinfo20(signal, scanptr.p, tcConnectptr.p); releaseOprec(signal); }//if ndbrequire(scanptr.p->scanCompletedOperations < MAX_PARALLEL_OP_PER_SCAN); scanptr.p->scanOpLength[scanptr.p->scanCompletedOperations] = tdata4; scanptr.p->scanCompletedOperations++; if ((scanptr.p->scanCompletedOperations == scanptr.p->scanConcurrentOperations) && (scanptr.p->scanLockHold == ZTRUE)) { jam(); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); return; } else if (scanptr.p->scanCompletedOperations == scanptr.p->scanConcurrentOperations) { jam(); scanptr.p->scanReleaseCounter = scanptr.p->scanCompletedOperations; 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; }//if 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 = scanptr.p->scanAccOpPtr[scanptr.p->scanCompletedOperations]; } else if (scanptr.p->scanFlag == NextScanReq::ZSCAN_NEXT_COMMIT) { jam(); accOpPtr = scanptr.p->scanAccOpPtr[scanptr.p->scanCompletedOperations - 1]; } 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->scanCompletedOperations > 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->scanCompletedOperations++; scanptr.p->scanReleaseCounter = scanptr.p->scanCompletedOperations; }//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->scanCompletedOperations > 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->scanCompletedOperations + 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->scanCompletedOperations = 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_ACC_OP_PTR TO RNIL IN SCAN RECORD ======= * * SUBROUTINE SHORT NAME = ISA * ========================================================================= */ void Dblqh::initScanAccOp(Signal* signal) { UintR tisaIndex; for (tisaIndex = 0; tisaIndex < MAX_PARALLEL_OP_PER_SCAN; tisaIndex++) { scanptr.p->scanAccOpPtr[tisaIndex] = RNIL; }//for }//Dblqh::initScanAccOp() /* ========================================================================= * ======= INITIATE SCAN RECORD ======= * * SUBROUTINE SHORT NAME = ISC * ========================================================================= */ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) { const Uint32 reqinfo = scanFragReq->requestInfo; const Uint32 scanConcurrentOperations = ScanFragReq::getConcurrency(reqinfo); 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->scanCompletedOperations = 0; scanptr.p->scanConcurrentOperations = scanConcurrentOperations; 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 = ZNIL; for (Uint32 i = 0; i < scanConcurrentOperations; i++) { jam(); scanptr.p->scanApiOpPtr[i] = scanFragReq->clientOpPtr[i]; scanptr.p->scanOpLength[i] = 0; scanptr.p->scanAccOpPtr[i] = 0; }//for /** * 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 c_scanTakeOverHash.add(scanptr); } return ZOK; #if 0 if (! rangeScan) { jam(); for (Int32 i = NR_ScanNo - 1; i >= 0; i--) { jam(); if (fragptr.p->fragScanRec[i] == ZNIL) { jam(); scanptr.p->scanNumber = i; fragptr.p->fragScanRec[i] = scanptr.i; return ZOK; }//if }//for } else { jam(); // put in second half of fragScanRec of primary table fragment FragrecordPtr tFragPtr; tFragPtr.i = fragptr.p->tableFragptr; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); for (Uint32 i = NR_MinRangeScanNo; i < NR_MaxRangeScanNo; i++) { if (tFragPtr.p->fragScanRec[i] == ZNIL) { jam(); scanptr.p->scanNumber = i; tFragPtr.p->fragScanRec[i] = scanptr.i; return ZOK; } } } return ZNO_FREE_FRAG_SCAN_REC_ERROR; #endif }//Dblqh::initScanrec() /* ========================================================================= * ======= 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; tabptr.p->usageCount++; }//Dblqh::initScanTc() /* ========================================================================= * ======= FINISH SCAN RECORD ======= * * REMOVE SCAN RECORD FROM PER FRAGMENT LIST. * ========================================================================= */ void Dblqh::finishScanrec(Signal* signal) { 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; 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); } 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->scanConcurrentOperations; cscanNoFreeRec++; }//Dblqh::releaseScanrec() /* ------------------------------------------------------------------------ * ------- SEND KEYINFO20 TO API ------- * * ------------------------------------------------------------------------ */ void Dblqh::sendKeyinfo20(Signal* signal, ScanRecord * scanP, TcConnectionrec * tcConP) { ndbrequire(scanP->scanCompletedOperations < MAX_PARALLEL_OP_PER_SCAN); KeyInfo20 * keyInfo = (KeyInfo20 *)&signal->theData[0]; const Uint32 scanOp = scanP->scanCompletedOperations; keyInfo->clientOpPtr = scanP->scanApiOpPtr[scanOp]; keyInfo->keyLen = tcConP->primKeyLen; keyInfo->scanInfo_Node = KeyInfo20::setScanInfo(scanOp, scanP->scanNumber)+ (getOwnNodeId() << 16); keyInfo->transId1 = tcConP->transid[0]; keyInfo->transId2 = tcConP->transid[1]; const BlockReference ref = scanP->scanApiBlockref; const Uint32 keyLen = tcConP->primKeyLen; if(refToNode(ref) == getOwnNodeId()){ jam(); EXECUTE_DIRECT(refToBlock(ref), GSN_KEYINFO20, signal, 5 + keyLen); jamEntry(); return; } bool connectedToNode = getNodeInfo(refToNode(ref)).m_connected; if (ERROR_INSERTED(5029)){ // Use error insert to turn routing on jam(); connectedToNode = false; } if (connectedToNode){ jam(); Uint32 keyLenLeft = keyLen; Uint32 keyDataIndex = 20; for(; keyLenLeft > 20; keyLenLeft -= 20, keyDataIndex += 20){ jam(); sendSignal(ref, GSN_KEYINFO20, signal, 25, JBB); for(Uint32 i = 0; i<20; i++) keyInfo->keyData[i] = keyInfo->keyData[keyDataIndex + i]; }//for sendSignal(ref, GSN_KEYINFO20, signal, 5 + keyLenLeft, JBB); } else { /** * If this node does not have a direct connection * to the receiving node we want to send the signals * routed via the control node */ jam(); Uint32 keyLenLeft = keyLen; Uint32 keyDataIndex = 19; BlockReference routeBlockref = tcConP->clientBlockref; for(; keyLenLeft > 19; keyLenLeft -= 19, keyDataIndex += 19){ jam(); // store final destination, but save original value Uint32 saveOne = keyInfo->keyData[19]; keyInfo->keyData[19] = ref; sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, 25, JBB); keyInfo->keyData[19] = saveOne; for(Uint32 i = 0; i<19; i++){ keyInfo->keyData[i] = keyInfo->keyData[keyDataIndex + i]; } }//for keyInfo->keyData[keyLenLeft] = ref; sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, 5 + keyLenLeft + 1, JBB); } }//Dblqh::sendKeyinfo20() /* ------------------------------------------------------------------------ * ------- SEND SCAN_FRAGCONF TO TC THAT CONTROLS THE SCAN ------- * * ------------------------------------------------------------------------ */ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) { scanptr.p->scanTcWaiting = ZFALSE; ScanFragConf * conf = (ScanFragConf*)&signal->theData[0]; conf->senderData = tcConnectptr.p->clientConnectrec; conf->completedOps = scanptr.p->scanCompletedOperations; conf->fragmentCompleted = scanCompleted; for(Uint32 i = 0; i<MAX_PARALLEL_OP_PER_SCAN; i++) conf->opReturnDataLen[i] = scanptr.p->scanOpLength[i]; conf->transId1 = tcConnectptr.p->transid[0]; conf->transId2 = tcConnectptr.p->transid[1]; 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 scanConcurrentOperations. // This variable has to be set-up here since it is used by releaseScanrec // to unbook operation records in ACC. /* ------------------------------------------------------------------------- */ scanptr.p->scanConcurrentOperations = 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; } scanptr.p->scanAccOpPtr[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, &signal->theData[3], 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; signal->theData[0] = scanptr.p->scanAccPtr; signal->theData[1] = scanptr.p->scanAccOpPtr[0]; 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 */ }//if /*---------------*/ /* 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); if (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); return; } else { jam(); 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); return; }//if }//if }//if 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(); lcpPtr.p->lcpState = LcpRecord::LCP_BLOCKED_COMP; 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 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; do { ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clsLcpLocptr.p->lcpLocstate != LcpLocRecord::ACC_STARTED) { ndbrequire((clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_COMPLETED) || (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED)); return; }//if clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; } while (clsLcpLocptr.i != RNIL); clsLcpLocptr.i = lcpPtr.p->firstLcpLocTup; do { ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); if (clsLcpLocptr.p->lcpLocstate != LcpLocRecord::TUP_STARTED) { ndbrequire((clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_COMPLETED) || (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED)); return; }//if clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; } 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; sacLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; do { ptrCheckGuard(sacLcpLocptr, clcpLocrecFileSize, lcpLocRecord); sacLcpLocptr.p->accContCounter = 0; /* ------------------------------------------------------------------------- */ /*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); 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) { #if 0 case LogFileRecord::BOTH_WRITES_ONGOING: jam(); ndbout_c("not crashing!!"); // Fall-through #endif case LogFileRecord::NOT_ONGOING: jam(); checkGcpCompleted(signal, ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1), lfoPtr.p->lfoWordWritten); break; 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)) { jam(); /* ---------------------------------------------------------------------- * FRAGMENT WAS NOT DEFINED YET. PUT IT IN. IF NO LOCAL CHECKPOINT EXISTED * THEN THE FRAGMENT HAS ALREADY BEEN ADDED. * ---------------------------------------------------------------------- */ if (!insertFragrec(signal, fragId)) { jam(); startFragRefLab(signal); return; }//if }//if tabptr.p->tableStatus = Tablerec::TABLE_DEFINED; initFragrec(signal, tabptr.i, fragId, ZPRIMARY_NODE); 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]; for (Uint32 i = 0; i < noLocFrag; i++) { fragid[i] = srFragidConf->fragId[i]; }//for for (Uint32 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. * ------------------------------------------------------------------- */ if (prevFragptr.i != RNIL) { jam(); ptrCheckGuard(prevFragptr, cfragrecFileSize, fragrecord); prevFragptr.p->nextFrag = fragptr.p->nextFrag; } else { jam(); cfirstCompletedFragSr = fragptr.p->nextFrag; }//if 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 = fragptr.p->nextFrag; }//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) { /* ------------------------------------------------------------------------ * 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); } 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; fragptr.i = RNIL; for (Uint32 i = (NO_OF_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 = (NO_OF_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++) { 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++) { 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++) { 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++) { 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) { switch (data) { case 0: jam(); for (Uint32 i = 0; i < MAX_NDB_NODES; i++) { cnodeSrState[i] = ZSTART_SR; cnodeExecSrState[i] = ZSTART_SR; }//for for (Uint32 i = 0; i < 1024; i++) { ctransidHash[i] = RNIL; }//for for (Uint32 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(); scanptr.p->scanType = ScanRecord::ST_IDLE; scanptr.p->scanState = ScanRecord::SCAN_FREE; scanptr.p->scanTcWaiting = ZFALSE; scanptr.p->nextHash = RNIL; scanptr.p->prevHash = RNIL; } tmp.release(); }//Dblqh::initialiseScanrec() /* ========================================================================== * ======= INITIATE TABLE RECORD ======= * * ========================================================================= */ void Dblqh::initialiseTabrec(Signal* signal) { if (ctabrecFileSize != 0) { for (tabptr.i = 0; tabptr.i < ctabrecFileSize; tabptr.i++) { ptrAss(tabptr, tablerec); tabptr.p->tableStatus = Tablerec::NOT_DEFINED; tabptr.p->usageCount = 0; for (Uint32 i = 0; i <= (NO_OF_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++) { 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; }//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 = (NO_OF_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->scanCompletedOperations, sp.p->scanConcurrentOperations); 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[TlcpPtr.p->m_EMPTY_LCP_REQ.TextLength+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; }