diff options
Diffstat (limited to 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp')
-rw-r--r-- | storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 18661 |
1 files changed, 18661 insertions, 0 deletions
diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp new file mode 100644 index 00000000000..c34d4ddb566 --- /dev/null +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -0,0 +1,18661 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#define DBLQH_C +#include "Dblqh.hpp" +#include <ndb_limits.h> +#include <md5_hash.hpp> + +#include <ndb_version.h> +#include <signaldata/TuxBound.hpp> +#include <signaldata/AccScan.hpp> +#include <signaldata/CopyActive.hpp> +#include <signaldata/CopyFrag.hpp> +#include <signaldata/CreateTrig.hpp> +#include <signaldata/DropTrig.hpp> +#include <signaldata/EmptyLcp.hpp> +#include <signaldata/EventReport.hpp> +#include <signaldata/ExecFragReq.hpp> +#include <signaldata/GCPSave.hpp> +#include <signaldata/TcKeyRef.hpp> +#include <signaldata/LqhKey.hpp> +#include <signaldata/NextScan.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> +#include <signaldata/ReadNodesConf.hpp> +#include <signaldata/RelTabMem.hpp> +#include <signaldata/ScanFrag.hpp> +#include <signaldata/SrFragidConf.hpp> +#include <signaldata/StartFragReq.hpp> +#include <signaldata/StartRec.hpp> +#include <signaldata/TupKey.hpp> +#include <signaldata/TupCommit.hpp> +#include <signaldata/LqhFrag.hpp> +#include <signaldata/AccFrag.hpp> +#include <signaldata/TupFrag.hpp> +#include <signaldata/DumpStateOrd.hpp> +#include <signaldata/PackedSignal.hpp> + +#include <signaldata/PrepDropTab.hpp> +#include <signaldata/DropTab.hpp> + +#include <signaldata/AlterTab.hpp> + +#include <signaldata/LCP.hpp> + +// Use DEBUG to print messages that should be +// seen only when we debug the product +#ifdef VM_TRACE +#define DEBUG(x) ndbout << "DBLQH: "<< x << endl; +NdbOut & +operator<<(NdbOut& out, Dblqh::TcConnectionrec::TransactionState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::TcConnectionrec::LogWriteState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::TcConnectionrec::ListState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::TcConnectionrec::AbortState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::ScanRecord::ScanState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::LogFileOperationRecord::LfoState state){ + out << (int)state; + return out; +} + +NdbOut & +operator<<(NdbOut& out, Dblqh::ScanRecord::ScanType state){ + out << (int)state; + return out; +} + +#else +#define DEBUG(x) +#endif + +//#define MARKER_TRACE 1 +//#define TRACE_SCAN_TAKEOVER 1 + +const Uint32 NR_ScanNo = 0; + +void Dblqh::execACC_COM_BLOCK(Signal* signal) +{ + jamEntry(); +/* ------------------------------------------------------------------------- */ +// Undo log buffer in ACC is in critical sector of being full. +/* ------------------------------------------------------------------------- */ + cCounterAccCommitBlocked++; + caccCommitBlocked = true; + cCommitBlocked = true; + return; +}//Dblqh::execACC_COM_BLOCK() + +void Dblqh::execACC_COM_UNBLOCK(Signal* signal) +{ + jamEntry(); +/* ------------------------------------------------------------------------- */ +// Undo log buffer in ACC ok again. +/* ------------------------------------------------------------------------- */ + caccCommitBlocked = false; + if (ctupCommitBlocked == false) { + jam(); + cCommitBlocked = false; + }//if + return; +}//Dblqh::execACC_COM_UNBLOCK() + +void Dblqh::execTUP_COM_BLOCK(Signal* signal) +{ + jamEntry(); +/* ------------------------------------------------------------------------- */ +// Undo log buffer in TUP is in critical sector of being full. +/* ------------------------------------------------------------------------- */ + cCounterTupCommitBlocked++; + ctupCommitBlocked = true; + cCommitBlocked = true; + return; +}//Dblqh::execTUP_COM_BLOCK() + +void Dblqh::execTUP_COM_UNBLOCK(Signal* signal) +{ + jamEntry(); +/* ------------------------------------------------------------------------- */ +// Undo log buffer in TUP ok again. +/* ------------------------------------------------------------------------- */ + ctupCommitBlocked = false; + if (caccCommitBlocked == false) { + jam(); + cCommitBlocked = false; + }//if + return; +}//Dblqh::execTUP_COM_UNBLOCK() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND SYSTEM ERROR ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::systemError(Signal* signal) +{ + progError(0, 0); +}//Dblqh::systemError() + +/* *************** */ +/* ACCSEIZEREF > */ +/* *************** */ +void Dblqh::execACCSEIZEREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execACCSEIZEREF() + +/* ******************************************************>> */ +/* THIS SIGNAL IS USED TO HANDLE REAL-TIME */ +/* BREAKS THAT ARE NECESSARY TO ENSURE REAL-TIME */ +/* OPERATION OF LQH. */ +/* This signal is also used for signal loops, for example */ +/* the timeout handling for writing logs every second. */ +/* ******************************************************>> */ +void Dblqh::execCONTINUEB(Signal* signal) +{ + jamEntry(); + Uint32 tcase = signal->theData[0]; + Uint32 data0 = signal->theData[1]; + Uint32 data1 = signal->theData[2]; + Uint32 data2 = signal->theData[3]; +#if 0 + if (tcase == RNIL) { + tcConnectptr.i = data0; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + ndbout << "State = " << tcConnectptr.p->transactionState; + ndbout << " seqNoReplica = " << tcConnectptr.p->seqNoReplica; + ndbout << " tcNodeFailrec = " << tcConnectptr.p->tcNodeFailrec; + ndbout << " activeCreat = " << tcConnectptr.p->activeCreat; + ndbout << endl; + ndbout << "tupkeyData0 = " << tcConnectptr.p->tupkeyData[0]; + ndbout << "tupkeyData1 = " << tcConnectptr.p->tupkeyData[1]; + ndbout << "tupkeyData2 = " << tcConnectptr.p->tupkeyData[2]; + ndbout << "tupkeyData3 = " << tcConnectptr.p->tupkeyData[3]; + ndbout << endl; + ndbout << "abortState = " << tcConnectptr.p->abortState; + ndbout << "listState = " << tcConnectptr.p->listState; + ndbout << endl; + return; + }//if +#endif + switch (tcase) { + case ZLOG_LQHKEYREQ: + if (cnoOfLogPages == 0) { + jam(); + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); + return; + }//if + logPartPtr.i = data0; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + + tcConnectptr.i = logPartPtr.p->firstLogQueue; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if ((cCommitBlocked == true) && + (fragptr.p->fragActiveStatus == ZTRUE)) { + jam(); + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); + return; + }//if + logPartPtr.p->LogLqhKeyReqSent = ZFALSE; + getFirstInLogQueue(signal); + + switch (tcConnectptr.p->transactionState) { + case TcConnectionrec::LOG_QUEUED: + if (tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE) { + jam(); + logNextStart(signal); + abortCommonLab(signal); + return; + } else { + jam(); +/*------------------------------------------------------------*/ +/* WE MUST SET THE STATE OF THE LOG PART TO IDLE TO */ +/* ENSURE THAT WE ARE NOT QUEUED AGAIN ON THE LOG PART */ +/* WE WILL SET THE LOG PART STATE TO ACTIVE IMMEDIATELY */ +/* SO NO OTHER PROCESS WILL SEE THIS STATE. IT IS MERELY*/ +/* USED TO ENABLE REUSE OF CODE. */ +/*------------------------------------------------------------*/ + if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { + jam(); + logPartPtr.p->logPartState = LogPartRecord::IDLE; + }//if + logLqhkeyreqLab(signal); + return; + }//if + break; + case TcConnectionrec::LOG_ABORT_QUEUED: + jam(); + writeAbortLog(signal); + removeLogTcrec(signal); + logNextStart(signal); + continueAfterLogAbortWriteLab(signal); + return; + break; + case TcConnectionrec::LOG_COMMIT_QUEUED: + case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: + jam(); + writeCommitLog(signal, logPartPtr); + logNextStart(signal); + if (tcConnectptr.p->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) { + if (tcConnectptr.p->seqNoReplica != 0) { + jam(); + commitReplyLab(signal); + } else { + jam(); + localCommitLab(signal); + }//if + return; + } else { + jam(); + tcConnectptr.p->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL; + return; + }//if + break; + case TcConnectionrec::COMMIT_QUEUED: + jam(); + logNextStart(signal); + localCommitLab(signal); + break; + case TcConnectionrec::ABORT_QUEUED: + jam(); + logNextStart(signal); + abortCommonLab(signal); + break; + default: + ndbrequire(false); + break; + }//switch + return; + break; + case ZSR_GCI_LIMITS: + jam(); + signal->theData[0] = data0; + srGciLimits(signal); + return; + break; + case ZSR_LOG_LIMITS: + jam(); + signal->theData[0] = data0; + signal->theData[1] = data1; + signal->theData[2] = data2; + srLogLimits(signal); + return; + break; + case ZSEND_EXEC_CONF: + jam(); + signal->theData[0] = data0; + sendExecConf(signal); + return; + break; + case ZEXEC_SR: + jam(); + signal->theData[0] = data0; + execSr(signal); + return; + break; + case ZSR_FOURTH_COMP: + jam(); + signal->theData[0] = data0; + srFourthComp(signal); + return; + break; + case ZINIT_FOURTH: + jam(); + signal->theData[0] = data0; + initFourth(signal); + return; + break; + case ZTIME_SUPERVISION: + jam(); + signal->theData[0] = data0; + timeSup(signal); + return; + break; + case ZSR_PHASE3_START: + jam(); + signal->theData[0] = data0; + srPhase3Start(signal); + return; + break; + case ZLQH_TRANS_NEXT: + jam(); + tcNodeFailptr.i = data0; + ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); + lqhTransNextLab(signal); + return; + break; + case ZSCAN_TC_CONNECT: + jam(); + tabptr.i = data1; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + scanTcConnectLab(signal, data0, data2); + return; + break; + case ZINITIALISE_RECORDS: + jam(); + initialiseRecordsLab(signal, data0, data2, signal->theData[4]); + return; + break; + case ZINIT_GCP_REC: + jam(); + gcpPtr.i = 0; + ptrAss(gcpPtr, gcpRecord); + initGcpRecLab(signal); + return; + break; + case ZRESTART_OPERATIONS_AFTER_STOP: + jam(); + tcConnectptr.i = data0; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + if (tcConnectptr.p->listState != TcConnectionrec::WAIT_QUEUE_LIST) { + jam(); + return; + }//if + releaseWaitQueue(signal); + linkActiveFrag(signal); + restartOperationsAfterStopLab(signal); + return; + break; + case ZCHECK_LCP_STOP_BLOCKED: + jam(); + c_scanRecordPool.getPtr(scanptr, data0); + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + checkLcpStopBlockedLab(signal); + return; + case ZSCAN_MARKERS: + jam(); + scanMarkers(signal, data0, data1, data2); + return; + break; + + case ZOPERATION_EVENT_REP: + jam(); + /* --------------------------------------------------------------------- */ + // Report information about transaction activity once per second. + /* --------------------------------------------------------------------- */ + if (signal->theData[1] == 0) { + signal->theData[0] = NDB_LE_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); + c_tup = (Dbtup*)globalData.getBlock(DBTUP); + ndbrequire(c_tup != 0); + return; + break; + default: + jam(); + /*empty*/; + sendsttorryLab(signal); + return; + break; + }//switch +}//Dblqh::execSTTOR() + +/* ***************************************> */ +/* Restart phases 1 - 6, sender is Ndbcntr */ +/* ***************************************> */ +void Dblqh::execNDB_STTOR(Signal* signal) +{ + jamEntry(); + Uint32 ownNodeId = signal->theData[1]; /* START PHASE*/ + cstartPhase = signal->theData[2]; /* MY NODE ID */ + cstartType = signal->theData[3]; /* START TYPE */ + + switch (cstartPhase) { + case ZSTART_PHASE1: + jam(); + preComputedRequestInfoMask = 0; + LqhKeyReq::setKeyLen(preComputedRequestInfoMask, RI_KEYLEN_MASK); + LqhKeyReq::setLastReplicaNo(preComputedRequestInfoMask, RI_LAST_REPL_MASK); + LqhKeyReq::setLockType(preComputedRequestInfoMask, RI_LOCK_TYPE_MASK); + // Dont LqhKeyReq::setApplicationAddressFlag + LqhKeyReq::setDirtyFlag(preComputedRequestInfoMask, 1); + // Dont LqhKeyReq::setInterpretedFlag + LqhKeyReq::setSimpleFlag(preComputedRequestInfoMask, 1); + LqhKeyReq::setOperation(preComputedRequestInfoMask, RI_OPERATION_MASK); + // Dont setAIInLqhKeyReq + // Dont setSeqNoReplica + // Dont setSameClientAndTcFlag + // Dont setReturnedReadLenAIFlag + // Dont setAPIVersion + LqhKeyReq::setMarkerFlag(preComputedRequestInfoMask, 1); + //preComputedRequestInfoMask = 0x003d7fff; + startphase1Lab(signal, /* dummy */ ~0, ownNodeId); + + signal->theData[0] = ZOPERATION_EVENT_REP; + signal->theData[1] = 1; + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); + return; + break; + case ZSTART_PHASE2: + jam(); + startphase2Lab(signal, /* dummy */ ~0); + return; + break; + case ZSTART_PHASE3: + jam(); + startphase3Lab(signal); + return; + break; + case ZSTART_PHASE4: + jam(); + startphase4Lab(signal); + return; + break; + case ZSTART_PHASE6: + jam(); + startphase6Lab(signal); + return; + break; + default: + jam(); + /*empty*/; + sendNdbSttorryLab(signal); + return; + break; + }//switch +}//Dblqh::execNDB_STTOR() + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* +++++++ START PHASE 1 +++++++ */ +/* LOAD OUR BLOCK REFERENCE AND OUR PROCESSOR ID */ +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +void Dblqh::sttorStartphase1Lab(Signal* signal) +{ + sendsttorryLab(signal); + return; +}//Dblqh::sttorStartphase1Lab() + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* +++++++ START PHASE 2 +++++++ */ +/* */ +/* INITIATE ALL RECORDS WITHIN THE BLOCK */ +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +void Dblqh::startphase1Lab(Signal* signal, Uint32 _dummy, Uint32 ownNodeId) +{ + UintR Ti; + HostRecordPtr ThostPtr; + +/* ------- INITIATE ALL RECORDS ------- */ + cownNodeid = ownNodeId; + caccBlockref = calcAccBlockRef (cownNodeid); + ctupBlockref = calcTupBlockRef (cownNodeid); + ctuxBlockref = calcTuxBlockRef (cownNodeid); + cownref = calcLqhBlockRef (cownNodeid); + for (Ti = 0; Ti < chostFileSize; Ti++) { + ThostPtr.i = Ti; + ptrCheckGuard(ThostPtr, chostFileSize, hostRecord); + ThostPtr.p->hostLqhBlockRef = calcLqhBlockRef(ThostPtr.i); + ThostPtr.p->hostTcBlockRef = calcTcBlockRef(ThostPtr.i); + ThostPtr.p->inPackedList = false; + ThostPtr.p->noOfPackedWordsLqh = 0; + ThostPtr.p->noOfPackedWordsTc = 0; + }//for + cpackedListIndex = 0; + sendNdbSttorryLab(signal); + return; +}//Dblqh::startphase1Lab() + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* +++++++ START PHASE 2 +++++++ */ +/* */ +/* CONNECT LQH WITH ACC AND TUP. */ +/* EVERY CONNECTION RECORD IN LQH IS ASSIGNED TO ONE ACC CONNECTION RECORD */ +/* AND ONE TUP CONNECTION RECORD. */ +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +void Dblqh::startphase2Lab(Signal* signal, Uint32 _dummy) +{ + cmaxWordsAtNodeRec = MAX_NO_WORDS_OUTSTANDING_COPY_FRAGMENT; +/* -- ACC AND TUP CONNECTION PROCESS -- */ + tcConnectptr.i = 0; + ptrAss(tcConnectptr, tcConnectionrec); + moreconnectionsLab(signal); + return; +}//Dblqh::startphase2Lab() + +void Dblqh::moreconnectionsLab(Signal* signal) +{ + tcConnectptr.p->tcAccBlockref = caccBlockref; + // set TUX block here (no operation is seized in TUX) + tcConnectptr.p->tcTuxBlockref = ctuxBlockref; +/* NO STATE CHECKING IS PERFORMED, ASSUMED TO WORK */ +/* *************** */ +/* ACCSEIZEREQ < */ +/* *************** */ + signal->theData[0] = tcConnectptr.i; + signal->theData[1] = cownref; + sendSignal(caccBlockref, GSN_ACCSEIZEREQ, signal, 2, JBB); + return; +}//Dblqh::moreconnectionsLab() + +/* ***************> */ +/* ACCSEIZECONF > */ +/* ***************> */ +void Dblqh::execACCSEIZECONF(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + tcConnectptr.p->accConnectrec = signal->theData[1]; +/* *************** */ +/* TUPSEIZEREQ < */ +/* *************** */ + tcConnectptr.p->tcTupBlockref = ctupBlockref; + signal->theData[0] = tcConnectptr.i; + signal->theData[1] = cownref; + sendSignal(ctupBlockref, GSN_TUPSEIZEREQ, signal, 2, JBB); + return; +}//Dblqh::execACCSEIZECONF() + +/* ***************> */ +/* TUPSEIZECONF > */ +/* ***************> */ +void Dblqh::execTUPSEIZECONF(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + tcConnectptr.p->tupConnectrec = signal->theData[1]; +/* ------- CHECK IF THERE ARE MORE CONNECTIONS TO BE CONNECTED ------- */ + tcConnectptr.i = tcConnectptr.p->nextTcConnectrec; + if (tcConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + moreconnectionsLab(signal); + return; + }//if +/* ALL LQH_CONNECT RECORDS ARE CONNECTED TO ACC AND TUP ---- */ + sendNdbSttorryLab(signal); + return; +}//Dblqh::execTUPSEIZECONF() + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* +++++++ START PHASE 4 +++++++ */ +/* */ +/* CONNECT LQH WITH LQH. */ +/* CONNECT EACH LQH WITH EVERY LQH IN THE DATABASE SYSTEM. */ +/* IF INITIAL START THEN CREATE THE FRAGMENT LOG FILES */ +/*IF SYSTEM RESTART OR NODE RESTART THEN OPEN THE FRAGMENT LOG FILES AND */ +/*FIND THE END OF THE LOG FILES. */ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* WAIT UNTIL ADD NODE PROCESSES ARE COMPLETED */ +/* IF INITIAL START ALSO WAIT FOR LOG FILES TO INITIALISED */ +/*START TIME SUPERVISION OF LOG FILES. WE HAVE TO WRITE LOG PAGES TO DISK */ +/*EVEN IF THE PAGES ARE NOT FULL TO ENSURE THAT THEY COME TO DISK ASAP. */ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +void Dblqh::startphase3Lab(Signal* signal) +{ + LogFileRecordPtr prevLogFilePtr; + LogFileRecordPtr zeroLogFilePtr; + + caddNodeState = ZTRUE; +/* ***************<< */ +/* READ_NODESREQ < */ +/* ***************<< */ + cinitialStartOngoing = ZTRUE; + ndbrequire(cnoLogFiles != 0); + + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + initLogpart(signal); + for (Uint32 fileNo = 0; fileNo < cnoLogFiles; fileNo++) { + seizeLogfile(signal); + if (fileNo != 0) { + jam(); + prevLogFilePtr.p->nextLogFile = logFilePtr.i; + logFilePtr.p->prevLogFile = prevLogFilePtr.i; + } else { + jam(); + logPartPtr.p->firstLogfile = logFilePtr.i; + logPartPtr.p->currentLogfile = logFilePtr.i; + zeroLogFilePtr.i = logFilePtr.i; + zeroLogFilePtr.p = logFilePtr.p; + }//if + prevLogFilePtr.i = logFilePtr.i; + prevLogFilePtr.p = logFilePtr.p; + initLogfile(signal, fileNo); + if ((cstartType == NodeState::ST_INITIAL_START) || + (cstartType == NodeState::ST_INITIAL_NODE_RESTART)) { + if (logFilePtr.i == zeroLogFilePtr.i) { + jam(); +/* ------------------------------------------------------------------------- */ +/*IN AN INITIAL START WE START BY CREATING ALL LOG FILES AND SETTING THEIR */ +/*PROPER SIZE AND INITIALISING PAGE ZERO IN ALL FILES. */ +/*WE START BY CREATING FILE ZERO IN EACH LOG PART AND THEN PROCEED */ +/*SEQUENTIALLY THROUGH ALL LOG FILES IN THE LOG PART. */ +/* ------------------------------------------------------------------------- */ + openLogfileInit(signal); + }//if + }//if + }//for + zeroLogFilePtr.p->prevLogFile = logFilePtr.i; + logFilePtr.p->nextLogFile = zeroLogFilePtr.i; + }//for + if (cstartType != NodeState::ST_INITIAL_START && + cstartType != NodeState::ST_INITIAL_NODE_RESTART) { + jam(); + ndbrequire(cstartType == NodeState::ST_NODE_RESTART || + cstartType == NodeState::ST_SYSTEM_RESTART); + /** -------------------------------------------------------------------- + * THIS CODE KICKS OFF THE SYSTEM RESTART AND NODE RESTART. IT STARTS UP + * THE RESTART BY FINDING THE END OF THE LOG AND FROM THERE FINDING THE + * INFO ABOUT THE GLOBAL CHECKPOINTS IN THE FRAGMENT LOG. + --------------------------------------------------------------------- */ + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + jam(); + LogFileRecordPtr locLogFilePtr; + ptrAss(logPartPtr, logPartRecord); + locLogFilePtr.i = logPartPtr.p->firstLogfile; + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FRONTPAGE; + openFileRw(signal, locLogFilePtr); + }//for + }//if + + signal->theData[0] = cownref; + sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB); + return; +}//Dblqh::startphase3Lab() + +/* ****************** */ +/* READ_NODESCONF > */ +/* ****************** */ +void Dblqh::execREAD_NODESCONF(Signal* signal) +{ + jamEntry(); + + ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0]; + cnoOfNodes = readNodes->noOfNodes; + + unsigned ind = 0; + unsigned i = 0; + for (i = 1; i < MAX_NDB_NODES; i++) { + jam(); + if (NodeBitmask::get(readNodes->allNodes, i)) { + jam(); + cnodeData[ind] = i; + cnodeStatus[ind] = NodeBitmask::get(readNodes->inactiveNodes, i); + //readNodes->getVersionId(i, readNodes->theVersionIds) not used + ind++; + }//if + }//for + ndbrequire(ind == cnoOfNodes); + ndbrequire(cnoOfNodes >= 1 && cnoOfNodes < MAX_NDB_NODES); + ndbrequire(!(cnoOfNodes == 1 && cstartType == NodeState::ST_NODE_RESTART)); + + caddNodeState = ZFALSE; + if (cstartType == NodeState::ST_SYSTEM_RESTART) { + jam(); + sendNdbSttorryLab(signal); + return; + }//if + checkStartCompletedLab(signal); + return; +}//Dblqh::execREAD_NODESCONF() + +void Dblqh::checkStartCompletedLab(Signal* signal) +{ + if (caddNodeState == ZFALSE) { + if (cinitialStartOngoing == ZFALSE) { + jam(); + sendNdbSttorryLab(signal); + return; + }//if + }//if + return; +}//Dblqh::checkStartCompletedLab() + +void Dblqh::startphase4Lab(Signal* signal) +{ + sendNdbSttorryLab(signal); + return; +}//Dblqh::startphase4Lab() + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* SET CONCURRENCY OF LOCAL CHECKPOINTS TO BE USED AFTER SYSTEM RESTART. */ +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +void Dblqh::startphase6Lab(Signal* signal) +{ + cstartPhase = ZNIL; + cstartType = ZNIL; + sendNdbSttorryLab(signal); + return; +}//Dblqh::startphase6Lab() + +void Dblqh::sendNdbSttorryLab(Signal* signal) +{ + signal->theData[0] = cownref; + sendSignal(NDBCNTR_REF, GSN_NDB_STTORRY, signal, 1, JBB); + return; +}//Dblqh::sendNdbSttorryLab() + +void Dblqh::sendsttorryLab(Signal* signal) +{ +/* *********<< */ +/* STTORRY < */ +/* *********<< */ + signal->theData[0] = csignalKey; /* SIGNAL KEY */ + signal->theData[1] = 3; /* BLOCK CATEGORY */ + signal->theData[2] = 2; /* SIGNAL VERSION NUMBER */ + signal->theData[3] = ZSTART_PHASE1; + signal->theData[4] = 255; + sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 5, JBB); + return; +}//Dblqh::sendsttorryLab() + +/* ***************>> */ +/* READ_NODESREF > */ +/* ***************>> */ +void Dblqh::execREAD_NODESREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execREAD_NODESREF() + +/* *************** */ +/* SIZEALT_REP > */ +/* *************** */ +void Dblqh::execREAD_CONFIG_REQ(Signal* signal) +{ + const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr(); + Uint32 ref = req->senderRef; + Uint32 senderData = req->senderData; + ndbrequire(req->noOfParameters == 0); + + jamEntry(); + + const ndb_mgm_configuration_iterator * p = + theConfiguration.getOwnConfigIterator(); + ndbrequire(p != 0); + + cnoLogFiles = 8; + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_REDOLOG_FILES, + &cnoLogFiles)); + ndbrequire(cnoLogFiles > 0); + + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_FRAG, &cfragrecFileSize)); + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TABLE, &ctabrecFileSize)); + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_TC_CONNECT, + &ctcConnectrecFileSize)); + clogFileFileSize = 4 * cnoLogFiles; + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_LQH_SCAN, &cscanrecFileSize)); + cmaxAccOps = cscanrecFileSize * MAX_PARALLEL_OP_PER_SCAN; + + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &c_diskless)); + + initRecords(); + initialiseRecordsLab(signal, 0, ref, senderData); + + return; +}//Dblqh::execSIZEALT_REP() + +/* ########################################################################## */ +/* ####### ADD/DELETE FRAGMENT MODULE ####### */ +/* THIS MODULE IS USED BY DICTIONARY TO CREATE NEW FRAGMENTS AND DELETE */ +/* OLD FRAGMENTS. */ +/* */ +/* ########################################################################## */ +/* -------------------------------------------------------------- */ +/* FRAG REQ */ +/* -------------------------------------------------------------- */ +/* *********************************************************> */ +/* LQHFRAGREQ: Create new fragments for a table. Sender DICT */ +/* *********************************************************> */ + +// this unbelievable mess could be replaced by one signal to LQH +// and execute direct to local DICT to get everything at once + +void Dblqh::execLQHFRAGREQ(Signal* signal) +{ + jamEntry(); + LqhFragReq * req = (LqhFragReq*)signal->getDataPtr(); + + Uint32 retPtr = req->senderData; + BlockReference retRef = req->senderRef; + Uint32 fragId = req->fragmentId; + Uint32 reqinfo = req->requestInfo; + tabptr.i = req->tableId; + Uint16 tlocalKeylen = req->localKeyLength; + Uint32 tmaxLoadFactor = req->maxLoadFactor; + Uint32 tminLoadFactor = req->minLoadFactor; + Uint8 tk = req->kValue; + Uint8 tlhstar = req->lh3DistrBits; + Uint8 tlh = req->lh3PageBits; + Uint32 tnoOfAttr = req->noOfAttributes; + Uint32 tnoOfNull = req->noOfNullAttributes; + Uint32 noOfAlloc = req->noOfPagesToPreAllocate; + Uint32 tschemaVersion = req->schemaVersion; + Uint32 ttupKeyLength = req->keyLength; + Uint32 nextLcp = req->nextLCP; + Uint32 noOfKeyAttr = req->noOfKeyAttr; + Uint32 noOfNewAttr = req->noOfNewAttr; + Uint32 checksumIndicator = req->checksumIndicator; + Uint32 noOfAttributeGroups = req->noOfAttributeGroups; + Uint32 gcpIndicator = req->GCPIndicator; + Uint32 startGci = req->startGci; + Uint32 tableType = req->tableType; + Uint32 primaryTableId = req->primaryTableId; + + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + bool tempTable = ((reqinfo & LqhFragReq::TemporaryTable) != 0); + + /* Temporary tables set to defined in system restart */ + if (tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ + tabptr.p->tableStatus = Tablerec::ADD_TABLE_ONGOING; + tabptr.p->tableType = tableType; + tabptr.p->primaryTableId = primaryTableId; + tabptr.p->schemaVersion = tschemaVersion; + }//if + + if (tabptr.p->tableStatus != Tablerec::ADD_TABLE_ONGOING){ + jam(); + fragrefLab(signal, retRef, retPtr, ZTAB_STATE_ERROR); + return; + }//if + //-------------------------------------------------------------------- + // We could arrive here if we create the fragment as part of a take + // over by a hot spare node. The table is then is already created + // and bit 31 is set, thus indicating that we are creating a fragment + // by copy creation. Also since the node has already been started we + // know that it is not a node restart ongoing. + //-------------------------------------------------------------------- + + if (getFragmentrec(signal, fragId)) { + jam(); + fragrefLab(signal, retRef, retPtr, terrorCode); + return; + }//if + if (!insertFragrec(signal, fragId)) { + jam(); + fragrefLab(signal, retRef, retPtr, terrorCode); + return; + }//if + Uint32 copyType = reqinfo & 3; + initFragrec(signal, tabptr.i, fragId, copyType); + fragptr.p->startGci = startGci; + fragptr.p->newestGci = startGci; + fragptr.p->tableType = tableType; + + if (DictTabInfo::isOrderedIndex(tableType)) { + jam(); + // find corresponding primary table fragment + TablerecPtr tTablePtr; + tTablePtr.i = primaryTableId; + ptrCheckGuard(tTablePtr, ctabrecFileSize, tablerec); + FragrecordPtr tFragPtr; + tFragPtr.i = RNIL; + for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) { + if (tTablePtr.p->fragid[i] == fragptr.p->fragId) { + jam(); + tFragPtr.i = tTablePtr.p->fragrec[i]; + break; + } + } + ndbrequire(tFragPtr.i != RNIL); + // store it + fragptr.p->tableFragptr = tFragPtr.i; + } else { + fragptr.p->tableFragptr = fragptr.i; + } + + if (tempTable) { +//-------------------------------------------- +// reqinfo bit 3-4 = 2 means temporary table +// without logging or checkpointing. +//-------------------------------------------- + jam(); + fragptr.p->logFlag = Fragrecord::STATE_FALSE; + fragptr.p->lcpFlag = Fragrecord::LCP_STATE_FALSE; + }//if + + fragptr.p->nextLcp = nextLcp; +//---------------------------------------------- +// For node restarts it is not necessarily zero +//---------------------------------------------- + if (cfirstfreeAddfragrec == RNIL) { + jam(); + deleteFragrec(fragId); + fragrefLab(signal, retRef, retPtr, ZNO_ADD_FRAGREC); + return; + }//if + seizeAddfragrec(signal); + addfragptr.p->addFragid = fragId; + addfragptr.p->fragmentPtr = fragptr.i; + addfragptr.p->dictBlockref = retRef; + addfragptr.p->dictConnectptr = retPtr; + addfragptr.p->m_senderAttrPtr = RNIL; + addfragptr.p->noOfAttr = tnoOfAttr; + addfragptr.p->noOfNull = tnoOfNull; + addfragptr.p->noOfAllocPages = noOfAlloc; + addfragptr.p->tabId = tabptr.i; + addfragptr.p->totalAttrReceived = 0; + addfragptr.p->attrSentToTup = ZNIL;/* TO FIND PROGRAMMING ERRORS QUICKLY */ + addfragptr.p->schemaVer = tschemaVersion; + Uint32 tmp = (reqinfo & LqhFragReq::CreateInRunning); + addfragptr.p->fragCopyCreation = (tmp == 0 ? 0 : 1); + addfragptr.p->addfragErrorCode = 0; + addfragptr.p->noOfKeyAttr = noOfKeyAttr; + addfragptr.p->noOfNewAttr = noOfNewAttr; + addfragptr.p->checksumIndicator = checksumIndicator; + addfragptr.p->noOfAttributeGroups = noOfAttributeGroups; + addfragptr.p->GCPIndicator = gcpIndicator; + addfragptr.p->lh3DistrBits = tlhstar; + addfragptr.p->tableType = tableType; + addfragptr.p->primaryTableId = primaryTableId; + // + addfragptr.p->tup1Connectptr = RNIL; + addfragptr.p->tup2Connectptr = RNIL; + addfragptr.p->tux1Connectptr = RNIL; + addfragptr.p->tux2Connectptr = RNIL; + + 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 = (fragId << 1) | 0; + addfragptr.p->fragid2 = (fragId << 1) | 1; + 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]; + 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; + + addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUP; + sendAddFragReq(signal); +}//Dblqh::execACCFRAGCONF() + +/* *************** */ +/* TUPFRAGCONF > */ +/* *************** */ +void Dblqh::execTUPFRAGCONF(Signal* signal) +{ + jamEntry(); + addfragptr.i = signal->theData[0]; + Uint32 tupConnectptr = signal->theData[1]; + Uint32 tupFragPtr = signal->theData[2]; /* TUP FRAGMENT POINTER */ + Uint32 localFragId = signal->theData[3]; /* LOCAL FRAGMENT ID */ + ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (localFragId == addfragptr.p->fragid1) { + jam(); + fragptr.p->tupFragptr[0] = tupFragPtr; + } else if (localFragId == addfragptr.p->fragid2) { + jam(); + fragptr.p->tupFragptr[1] = tupFragPtr; + } else { + ndbrequire(false); + return; + }//if + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::WAIT_TWO_TUP: + jam(); + fragptr.p->tupFragptr[0] = tupFragPtr; + addfragptr.p->tup1Connectptr = tupConnectptr; + addfragptr.p->addfragStatus = AddFragRecord::WAIT_ONE_TUP; + sendAddFragReq(signal); + break; + case AddFragRecord::WAIT_ONE_TUP: + jam(); + fragptr.p->tupFragptr[1] = tupFragPtr; + addfragptr.p->tup2Connectptr = tupConnectptr; + if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { + addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUX; + sendAddFragReq(signal); + break; + } + goto done_with_frag; + break; + case AddFragRecord::WAIT_TWO_TUX: + jam(); + fragptr.p->tuxFragptr[0] = tupFragPtr; + addfragptr.p->tux1Connectptr = tupConnectptr; + addfragptr.p->addfragStatus = AddFragRecord::WAIT_ONE_TUX; + sendAddFragReq(signal); + break; + case AddFragRecord::WAIT_ONE_TUX: + jam(); + fragptr.p->tuxFragptr[1] = tupFragPtr; + addfragptr.p->tux2Connectptr = tupConnectptr; + goto done_with_frag; + break; + done_with_frag: + /* ---------------------------------------------------------------- */ + /* Finished create of fragments. Now ready for creating attributes. */ + /* ---------------------------------------------------------------- */ + addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR; + { + LqhFragConf* conf = (LqhFragConf*)signal->getDataPtrSend(); + conf->senderData = addfragptr.p->dictConnectptr; + conf->lqhFragPtr = addfragptr.i; + sendSignal(addfragptr.p->dictBlockref, GSN_LQHFRAGCONF, + signal, LqhFragConf::SignalLength, JBB); + } + break; + default: + ndbrequire(false); + break; + } +}//Dblqh::execTUPFRAGCONF() + +/* *************** */ +/* TUXFRAGCONF > */ +/* *************** */ +void Dblqh::execTUXFRAGCONF(Signal* signal) +{ + jamEntry(); + execTUPFRAGCONF(signal); +}//Dblqh::execTUXFRAGCONF + +/* + * Add fragment in TUP or TUX. Called up to 4 times. + */ +void +Dblqh::sendAddFragReq(Signal* signal) +{ + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP || + addfragptr.p->addfragStatus == AddFragRecord::WAIT_ONE_TUP) { + if (DictTabInfo::isTable(addfragptr.p->tableType) || + DictTabInfo::isHashIndex(addfragptr.p->tableType)) { + jam(); + signal->theData[0] = addfragptr.i; + signal->theData[1] = cownref; + signal->theData[2] = 0; /* ADD TABLE */ + signal->theData[3] = addfragptr.p->tabId; + signal->theData[4] = addfragptr.p->noOfAttr; + signal->theData[5] = + addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP + ? addfragptr.p->fragid1 : addfragptr.p->fragid2; + signal->theData[6] = (addfragptr.p->noOfAllocPages >> 1) + 1; + signal->theData[7] = addfragptr.p->noOfNull; + signal->theData[8] = addfragptr.p->schemaVer; + signal->theData[9] = addfragptr.p->noOfKeyAttr; + signal->theData[10] = addfragptr.p->noOfNewAttr; + signal->theData[11] = addfragptr.p->checksumIndicator; + signal->theData[12] = addfragptr.p->noOfAttributeGroups; + signal->theData[13] = addfragptr.p->GCPIndicator; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, + signal, TupFragReq::SignalLength, JBB); + return; + } + if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { + jam(); + signal->theData[0] = addfragptr.i; + signal->theData[1] = cownref; + signal->theData[2] = 0; /* ADD TABLE */ + signal->theData[3] = addfragptr.p->tabId; + signal->theData[4] = 1; /* ordered index: one array attr */ + signal->theData[5] = + addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUP + ? addfragptr.p->fragid1 : addfragptr.p->fragid2; + signal->theData[6] = (addfragptr.p->noOfAllocPages >> 1) + 1; + signal->theData[7] = 0; /* ordered index: no nullable */ + signal->theData[8] = addfragptr.p->schemaVer; + signal->theData[9] = 1; /* ordered index: one key */ + signal->theData[10] = addfragptr.p->noOfNewAttr; + signal->theData[11] = addfragptr.p->checksumIndicator; + signal->theData[12] = addfragptr.p->noOfAttributeGroups; + signal->theData[13] = addfragptr.p->GCPIndicator; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, + signal, TupFragReq::SignalLength, JBB); + return; + } + } + if (addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX || + addfragptr.p->addfragStatus == AddFragRecord::WAIT_ONE_TUX) { + if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { + jam(); + TuxFragReq* const tuxreq = (TuxFragReq*)signal->getDataPtrSend(); + tuxreq->userPtr = addfragptr.i; + tuxreq->userRef = cownref; + tuxreq->reqInfo = 0; /* ADD TABLE */ + tuxreq->tableId = addfragptr.p->tabId; + ndbrequire(addfragptr.p->noOfAttr >= 2); + tuxreq->noOfAttr = addfragptr.p->noOfAttr - 1; /* skip NDB$TNODE */ + tuxreq->fragId = + addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX + ? addfragptr.p->fragid1: addfragptr.p->fragid2; + tuxreq->fragOff = addfragptr.p->lh3DistrBits; + tuxreq->tableType = addfragptr.p->tableType; + tuxreq->primaryTableId = addfragptr.p->primaryTableId; + // pointer to index fragment in TUP + tuxreq->tupIndexFragPtrI = + addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX ? + fragptr.p->tupFragptr[0] : fragptr.p->tupFragptr[1]; + // pointers to table fragments in TUP and ACC + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + tuxreq->tupTableFragPtrI[0] = tFragPtr.p->tupFragptr[0]; + tuxreq->tupTableFragPtrI[1] = tFragPtr.p->tupFragptr[1]; + tuxreq->accTableFragPtrI[0] = tFragPtr.p->accFragptr[0]; + tuxreq->accTableFragPtrI[1] = tFragPtr.p->accFragptr[1]; + sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, + signal, TuxFragReq::SignalLength, JBB); + return; + } + } + ndbrequire(false); +}//Dblqh::sendAddFragReq + +/* ************************************************************************> */ +/* LQHADDATTRREQ: Request from DICT to create attributes for the new table. */ +/* ************************************************************************> */ +void Dblqh::execLQHADDATTREQ(Signal* signal) +{ + jamEntry(); + LqhAddAttrReq * const req = (LqhAddAttrReq*)signal->getDataPtr(); + + addfragptr.i = req->lqhFragPtr; + const Uint32 tnoOfAttr = req->noOfAttributes; + const Uint32 senderData = req->senderData; + const Uint32 senderAttrPtr = req->senderAttrPtr; + + ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); + ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::WAIT_ADD_ATTR); + ndbrequire((tnoOfAttr != 0) && (tnoOfAttr <= LqhAddAttrReq::MAX_ATTRIBUTES)); + addfragptr.p->totalAttrReceived += tnoOfAttr; + ndbrequire(addfragptr.p->totalAttrReceived <= addfragptr.p->noOfAttr); + + addfragptr.p->attrReceived = tnoOfAttr; + for (Uint32 i = 0; i < tnoOfAttr; i++) { + addfragptr.p->attributes[i] = req->attributes[i]; + }//for + addfragptr.p->attrSentToTup = 0; + ndbrequire(addfragptr.p->dictConnectptr == senderData); + addfragptr.p->m_senderAttrPtr = senderAttrPtr; + addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT1; + sendAddAttrReq(signal); +}//Dblqh::execLQHADDATTREQ() + +/* *********************>> */ +/* TUP_ADD_ATTCONF > */ +/* *********************>> */ +void Dblqh::execTUP_ADD_ATTCONF(Signal* signal) +{ + jamEntry(); + addfragptr.i = signal->theData[0]; + // implies that operation was released on the other side + const bool lastAttr = signal->theData[1]; + ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::TUP_ATTR_WAIT1: + jam(); + if (lastAttr) + addfragptr.p->tup1Connectptr = RNIL; + addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT2; + sendAddAttrReq(signal); + break; + case AddFragRecord::TUP_ATTR_WAIT2: + jam(); + if (lastAttr) + addfragptr.p->tup2Connectptr = RNIL; + 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(); + if (lastAttr) + addfragptr.p->tux1Connectptr = RNIL; + addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT2; + sendAddAttrReq(signal); + break; + case AddFragRecord::TUX_ATTR_WAIT2: + jam(); + if (lastAttr) + addfragptr.p->tux2Connectptr = RNIL; + goto done_with_attr; + break; + done_with_attr: + addfragptr.p->attrSentToTup = addfragptr.p->attrSentToTup + 1; + ndbrequire(addfragptr.p->attrSentToTup <= addfragptr.p->attrReceived); + ndbrequire(addfragptr.p->totalAttrReceived <= addfragptr.p->noOfAttr); + if (addfragptr.p->attrSentToTup < addfragptr.p->attrReceived) { + // more in this batch + jam(); + addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT1; + sendAddAttrReq(signal); + } else if (addfragptr.p->totalAttrReceived < addfragptr.p->noOfAttr) { + // more batches to receive + jam(); + addfragptr.p->addfragStatus = AddFragRecord::WAIT_ADD_ATTR; + LqhAddAttrConf *const conf = (LqhAddAttrConf*)signal->getDataPtrSend(); + conf->senderData = addfragptr.p->dictConnectptr; + conf->senderAttrPtr = addfragptr.p->m_senderAttrPtr; + conf->fragId = addfragptr.p->addFragid; + sendSignal(addfragptr.p->dictBlockref, GSN_LQHADDATTCONF, + signal, LqhAddAttrConf::SignalLength, JBB); + } else { + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + /* ------------------------------------------------------------------ + * WE HAVE NOW COMPLETED ADDING THIS FRAGMENT. WE NOW NEED TO SET THE + * PROPER STATE IN FRAG_STATUS DEPENDENT ON IF WE ARE CREATING A NEW + * REPLICA OR IF WE ARE CREATING A TABLE. FOR FRAGMENTS IN COPY + * PROCESS WE DO NOT WANT LOGGING ACTIVATED. + * ----------------------------------------------------------------- */ + if (addfragptr.p->fragCopyCreation == 1) { + jam(); + if (! DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) + fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION; + else + fragptr.p->fragStatus = Fragrecord::FSACTIVE; + fragptr.p->logFlag = Fragrecord::STATE_FALSE; + } else { + jam(); + fragptr.p->fragStatus = Fragrecord::FSACTIVE; + }//if + LqhAddAttrConf *const conf = (LqhAddAttrConf*)signal->getDataPtrSend(); + conf->senderData = addfragptr.p->dictConnectptr; + conf->senderAttrPtr = addfragptr.p->m_senderAttrPtr; + conf->fragId = addfragptr.p->addFragid; + sendSignal(addfragptr.p->dictBlockref, GSN_LQHADDATTCONF, signal, + LqhAddAttrConf::SignalLength, JBB); + releaseAddfragrec(signal); + }//if + break; + default: + ndbrequire(false); + break; + } +} + +/* **********************>> */ +/* TUX_ADD_ATTRCONF > */ +/* **********************>> */ +void Dblqh::execTUX_ADD_ATTRCONF(Signal* signal) +{ + jamEntry(); + execTUP_ADD_ATTCONF(signal); +}//Dblqh::execTUX_ADD_ATTRCONF + +/* + * Add attribute in TUP or TUX. Called up to 4 times. + */ +void +Dblqh::sendAddAttrReq(Signal* signal) +{ + arrGuard(addfragptr.p->attrSentToTup, LqhAddAttrReq::MAX_ATTRIBUTES); + LqhAddAttrReq::Entry& entry = + addfragptr.p->attributes[addfragptr.p->attrSentToTup]; + const Uint32 attrId = entry.attrId & 0xffff; + const Uint32 primaryAttrId = entry.attrId >> 16; + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT1 || + addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT2) { + if (DictTabInfo::isTable(addfragptr.p->tableType) || + DictTabInfo::isHashIndex(addfragptr.p->tableType) || + (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && + primaryAttrId == ZNIL)) { + jam(); + TupAddAttrReq* const tupreq = (TupAddAttrReq*)signal->getDataPtrSend(); + tupreq->tupConnectPtr = + addfragptr.p->addfragStatus == AddFragRecord::TUP_ATTR_WAIT1 + ? addfragptr.p->tup1Connectptr : addfragptr.p->tup2Connectptr; + tupreq->notused1 = 0; + tupreq->attrId = attrId; + tupreq->attrDescriptor = entry.attrDescriptor; + tupreq->extTypeInfo = entry.extTypeInfo; + sendSignal(fragptr.p->tupBlockref, GSN_TUP_ADD_ATTRREQ, + signal, TupAddAttrReq::SignalLength, JBB); + return; + } + if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType) && + primaryAttrId != ZNIL) { + // this attribute is not for TUP + jam(); + TupAddAttrConf* tupconf = (TupAddAttrConf*)signal->getDataPtrSend(); + tupconf->userPtr = addfragptr.i; + tupconf->lastAttr = false; + 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; + tuxconf->lastAttr = false; + 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() + +/* + * Abort on-going ops. + */ +void Dblqh::abortAddFragOps(Signal* signal) +{ + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + signal->theData[0] = (Uint32)-1; + if (addfragptr.p->tup1Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tup1Connectptr; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, 2, JBB); + addfragptr.p->tup1Connectptr = RNIL; + } + if (addfragptr.p->tup2Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tup2Connectptr; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, 2, JBB); + addfragptr.p->tup2Connectptr = RNIL; + } + if (addfragptr.p->tux1Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tux1Connectptr; + sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, signal, 2, JBB); + addfragptr.p->tux1Connectptr = RNIL; + } + if (addfragptr.p->tux2Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tux2Connectptr; + sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, signal, 2, JBB); + addfragptr.p->tux2Connectptr = RNIL; + } +} + +/* ************>> */ +/* 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; + + // no operation to release, just add some jams + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::WAIT_TWO_TUP: + jam(); + break; + case AddFragRecord::WAIT_ONE_TUP: + jam(); + break; + case AddFragRecord::WAIT_TWO_TUX: + jam(); + break; + case AddFragRecord::WAIT_ONE_TUX: + jam(); + break; + default: + ndbrequire(false); + break; + } + abortAddFragOps(signal); + + 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; + + // operation was released on the other side + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::TUP_ATTR_WAIT1: + jam(); + ndbrequire(addfragptr.p->tup1Connectptr != RNIL); + addfragptr.p->tup1Connectptr = RNIL; + break; + case AddFragRecord::TUP_ATTR_WAIT2: + jam(); + ndbrequire(addfragptr.p->tup2Connectptr != RNIL); + addfragptr.p->tup2Connectptr = RNIL; + break; + case AddFragRecord::TUX_ATTR_WAIT1: + jam(); + ndbrequire(addfragptr.p->tux1Connectptr != RNIL); + addfragptr.p->tux1Connectptr = RNIL; + break; + case AddFragRecord::TUX_ATTR_WAIT2: + jam(); + ndbrequire(addfragptr.p->tux2Connectptr != RNIL); + addfragptr.p->tux2Connectptr = RNIL; + break; + default: + ndbrequire(false); + break; + } + abortAddFragOps(signal); + + const Uint32 Ref = addfragptr.p->dictBlockref; + const Uint32 senderData = addfragptr.p->dictConnectptr; + const Uint32 errorCode = addfragptr.p->addfragErrorCode; + releaseAddfragrec(signal); + + LqhAddAttrRef *const ref = (LqhAddAttrRef*)signal->getDataPtrSend(); + ref->senderData = senderData; + ref->errorCode = errorCode; + sendSignal(Ref, GSN_LQHADDATTREF, signal, + LqhAddAttrRef::SignalLength, JBB); + +}//Dblqh::execTUP_ADD_ATTRREF() + +/* **********************> */ +/* TUX_ADD_ATTRREF > */ +/* **********************> */ +void Dblqh::execTUX_ADD_ATTRREF(Signal* signal) +{ + jamEntry(); + execTUP_ADD_ATTRREF(signal); +}//Dblqh::execTUX_ADD_ATTRREF + +void +Dblqh::execPREP_DROP_TAB_REQ(Signal* signal){ + jamEntry(); + + PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); + + Uint32 senderRef = req->senderRef; + Uint32 senderData = req->senderData; + + TablerecPtr tabPtr; + tabPtr.i = req->tableId; + ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); + + Uint32 errCode = 0; + errCode = checkDropTabState(tabPtr.p->tableStatus, GSN_PREP_DROP_TAB_REQ); + if(errCode != 0){ + jam(); + + PrepDropTabRef* ref = (PrepDropTabRef*)signal->getDataPtrSend(); + ref->senderRef = reference(); + ref->senderData = senderData; + ref->tableId = tabPtr.i; + ref->errorCode = errCode; + sendSignal(senderRef, GSN_PREP_DROP_TAB_REF, signal, + PrepDropTabRef::SignalLength, JBB); + return; + } + + tabPtr.p->tableStatus = Tablerec::PREP_DROP_TABLE_ONGOING; + tabPtr.p->waitingTC.clear(); + tabPtr.p->waitingDIH.clear(); + + PrepDropTabConf * conf = (PrepDropTabConf*)signal->getDataPtrSend(); + conf->tableId = tabPtr.i; + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(senderRef, GSN_PREP_DROP_TAB_CONF, signal, + PrepDropTabConf::SignalLength, JBB); + + signal->theData[0] = ZPREP_DROP_TABLE; + signal->theData[1] = tabPtr.i; + signal->theData[2] = senderRef; + signal->theData[3] = senderData; + checkDropTab(signal); +} + +void +Dblqh::checkDropTab(Signal* signal){ + + TablerecPtr tabPtr; + tabPtr.i = signal->theData[1]; + ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); + + ndbrequire(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING); + + if(tabPtr.p->usageCount > 0){ + jam(); + sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 4); + return; + } + + bool lcpDone = true; + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + if(lcpPtr.p->lcpState != LcpRecord::LCP_IDLE){ + jam(); + + if(lcpPtr.p->currentFragment.lcpFragOrd.tableId == tabPtr.i){ + jam(); + lcpDone = false; + } + + if(lcpPtr.p->lcpQueued && + lcpPtr.p->queuedFragment.lcpFragOrd.tableId == tabPtr.i){ + jam(); + lcpDone = false; + } + } + + if(!lcpDone){ + jam(); + sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 4); + return; + } + + tabPtr.p->tableStatus = Tablerec::PREP_DROP_TABLE_DONE; + + WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtrSend(); + conf->tableId = tabPtr.i; + conf->senderRef = reference(); + for(Uint32 i = 1; i<MAX_NDB_NODES; i++){ + if(tabPtr.p->waitingTC.get(i)){ + tabPtr.p->waitingTC.clear(i); + sendSignal(calcTcBlockRef(i), GSN_WAIT_DROP_TAB_CONF, signal, + WaitDropTabConf::SignalLength, JBB); + } + if(tabPtr.p->waitingDIH.get(i)){ + tabPtr.p->waitingDIH.clear(i); + sendSignal(calcDihBlockRef(i), GSN_WAIT_DROP_TAB_CONF, signal, + WaitDropTabConf::SignalLength, JBB); + } + } +} + +void +Dblqh::execWAIT_DROP_TAB_REQ(Signal* signal){ + jamEntry(); + WaitDropTabReq * req = (WaitDropTabReq*)signal->getDataPtr(); + + TablerecPtr tabPtr; + tabPtr.i = req->tableId; + ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); + + Uint32 senderRef = req->senderRef; + Uint32 nodeId = refToNode(senderRef); + Uint32 blockNo = refToBlock(senderRef); + + if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING){ + jam(); + switch(blockNo){ + case DBTC: + tabPtr.p->waitingTC.set(nodeId); + break; + case DBDIH: + tabPtr.p->waitingDIH.set(nodeId); + break; + default: + ndbrequire(false); + } + return; + } + + if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ + jam(); + WaitDropTabConf * conf = (WaitDropTabConf*)signal->getDataPtrSend(); + conf->tableId = tabPtr.i; + conf->senderRef = reference(); + sendSignal(senderRef, GSN_WAIT_DROP_TAB_CONF, signal, + WaitDropTabConf::SignalLength, JBB); + return; + } + + WaitDropTabRef * ref = (WaitDropTabRef*)signal->getDataPtrSend(); + ref->tableId = tabPtr.i; + ref->senderRef = reference(); + + bool ok = false; + switch(tabPtr.p->tableStatus){ + case Tablerec::TABLE_DEFINED: + ok = true; + ref->errorCode = WaitDropTabRef::IllegalTableState; + break; + case Tablerec::NOT_DEFINED: + ok = true; + ref->errorCode = WaitDropTabRef::NoSuchTable; + break; + case Tablerec::ADD_TABLE_ONGOING: + ok = true; + ref->errorCode = WaitDropTabRef::IllegalTableState; + break; + case Tablerec::PREP_DROP_TABLE_ONGOING: + case Tablerec::PREP_DROP_TABLE_DONE: + // Should have been take care of above + ndbrequire(false); + } + ndbrequire(ok); + ref->tableStatus = tabPtr.p->tableStatus; + sendSignal(senderRef, GSN_WAIT_DROP_TAB_REF, signal, + WaitDropTabRef::SignalLength, JBB); + return; +} + +void +Dblqh::execDROP_TAB_REQ(Signal* signal){ + jamEntry(); + + DropTabReq* req = (DropTabReq*)signal->getDataPtr(); + + Uint32 senderRef = req->senderRef; + Uint32 senderData = req->senderData; + + TablerecPtr tabPtr; + tabPtr.i = req->tableId; + ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); + + do { + if(req->requestType == DropTabReq::RestartDropTab){ + jam(); + break; + } + + if(req->requestType == DropTabReq::OnlineDropTab){ + jam(); + Uint32 errCode = 0; + errCode = checkDropTabState(tabPtr.p->tableStatus, GSN_DROP_TAB_REQ); + if(errCode != 0){ + jam(); + + DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend(); + ref->senderRef = reference(); + ref->senderData = senderData; + ref->tableId = tabPtr.i; + ref->errorCode = errCode; + sendSignal(senderRef, GSN_DROP_TAB_REF, signal, + DropTabRef::SignalLength, JBB); + return; + } + } + + removeTable(tabPtr.i); + + } while(false); + + ndbrequire(tabPtr.p->usageCount == 0); + tabPtr.p->tableStatus = Tablerec::NOT_DEFINED; + + DropTabConf * const dropConf = (DropTabConf *)signal->getDataPtrSend(); + dropConf->senderRef = reference(); + dropConf->senderData = senderData; + dropConf->tableId = tabPtr.i; + sendSignal(senderRef, GSN_DROP_TAB_CONF, + signal, DropTabConf::SignalLength, JBB); +} + +Uint32 +Dblqh::checkDropTabState(Tablerec::TableStatus status, Uint32 gsn) const{ + + if(gsn == GSN_PREP_DROP_TAB_REQ){ + switch(status){ + case Tablerec::NOT_DEFINED: + jam(); + // Fall through + case Tablerec::ADD_TABLE_ONGOING: + jam(); + return PrepDropTabRef::NoSuchTable; + break; + case Tablerec::PREP_DROP_TABLE_ONGOING: + jam(); + return PrepDropTabRef::PrepDropInProgress; + break; + case Tablerec::PREP_DROP_TABLE_DONE: + jam(); + return PrepDropTabRef::DropInProgress; + break; + case Tablerec::TABLE_DEFINED: + jam(); + return 0; + break; + } + ndbrequire(0); + } + + if(gsn == GSN_DROP_TAB_REQ){ + switch(status){ + case Tablerec::NOT_DEFINED: + jam(); + // Fall through + case Tablerec::ADD_TABLE_ONGOING: + jam(); + return DropTabRef::NoSuchTable; + break; + case Tablerec::PREP_DROP_TABLE_ONGOING: + jam(); + return DropTabRef::PrepDropInProgress; + break; + case Tablerec::PREP_DROP_TABLE_DONE: + jam(); + return 0; + break; + case Tablerec::TABLE_DEFINED: + jam(); + return DropTabRef::DropWoPrep; + } + ndbrequire(0); + } + ndbrequire(0); + return RNIL; +} + +void Dblqh::removeTable(Uint32 tableId) +{ + tabptr.i = tableId; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + + for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { + jam(); + if (tabptr.p->fragid[i] != ZNIL) { + jam(); + deleteFragrec(tabptr.p->fragid[i]); + }//if + }//for +}//Dblqh::removeTable() + +void +Dblqh::execALTER_TAB_REQ(Signal* signal) +{ + jamEntry(); + AlterTabReq* const req = (AlterTabReq*)signal->getDataPtr(); + const Uint32 senderRef = req->senderRef; + const Uint32 senderData = req->senderData; + const Uint32 changeMask = req->changeMask; + const Uint32 tableId = req->tableId; + const Uint32 tableVersion = req->tableVersion; + const Uint32 gci = req->gci; + AlterTabReq::RequestType requestType = + (AlterTabReq::RequestType) req->requestType; + + TablerecPtr tablePtr; + tablePtr.i = tableId; + ptrCheckGuard(tablePtr, ctabrecFileSize, tablerec); + tablePtr.p->schemaVersion = tableVersion; + + // Request handled successfully + AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + conf->changeMask = changeMask; + conf->tableId = tableId; + conf->tableVersion = tableVersion; + conf->gci = gci; + conf->requestType = requestType; + sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal, + AlterTabConf::SignalLength, JBB); +} + +/* ************************************************************************>> + * TIME_SIGNAL: Handles time-out of local operations. This is a clean-up + * handler. If no other measure has succeeded in cleaning up after time-outs + * or else then this routine will remove the transaction after 120 seconds of + * inactivity. The check is performed once per 10 second. Sender is QMGR. + * ************************************************************************>> */ +void Dblqh::execTIME_SIGNAL(Signal* signal) +{ + jamEntry(); + cLqhTimeOutCount++; + cLqhTimeOutCheckCount++; + if ((cCounterAccCommitBlocked > 0) || + (cCounterTupCommitBlocked > 0)) { + jam(); + signal->theData[0] = NDB_LE_UndoLogBlocked; + signal->theData[1] = cCounterTupCommitBlocked; + signal->theData[2] = cCounterAccCommitBlocked; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB); + + cCounterTupCommitBlocked = 0; + cCounterAccCommitBlocked = 0; + }//if + if (cLqhTimeOutCheckCount < 10) { + jam(); + return; + }//if + cLqhTimeOutCheckCount = 0; +#ifdef VM_TRACE + TcConnectionrecPtr tTcConptr; + + for (tTcConptr.i = 0; tTcConptr.i < ctcConnectrecFileSize; + tTcConptr.i++) { + jam(); + ptrAss(tTcConptr, tcConnectionrec); + if ((tTcConptr.p->tcTimer != 0) && + ((tTcConptr.p->tcTimer + 120) < cLqhTimeOutCount)) { + ndbout << "Dblqh::execTIME_SIGNAL"<<endl + << "Timeout found in tcConnectRecord " <<tTcConptr.i<<endl + << " cLqhTimeOutCount = " << cLqhTimeOutCount << endl + << " tcTimer="<<tTcConptr.p->tcTimer<<endl + << " tcTimer+120="<<tTcConptr.p->tcTimer + 120<<endl; + + ndbout << " transactionState = " << tTcConptr.p->transactionState<<endl; + ndbout << " operation = " << tTcConptr.p->operation<<endl; + ndbout << " tcNodeFailrec = " << tTcConptr.p->tcNodeFailrec + << " seqNoReplica = " << tTcConptr.p->seqNoReplica + << " simpleRead = " << tTcConptr.p->simpleRead + << endl; + ndbout << " replicaType = " << tTcConptr.p->replicaType + << " reclenAiLqhkey = " << tTcConptr.p->reclenAiLqhkey + << " opExec = " << tTcConptr.p->opExec + << endl; + ndbout << " opSimple = " << tTcConptr.p->opSimple + << " nextSeqNoReplica = " << tTcConptr.p->nextSeqNoReplica + << " lockType = " << tTcConptr.p->lockType + << " localFragptr = " << tTcConptr.p->localFragptr + << endl; + ndbout << " lastReplicaNo = " << tTcConptr.p->lastReplicaNo + << " indTakeOver = " << tTcConptr.p->indTakeOver + << " dirtyOp = " << tTcConptr.p->dirtyOp + << endl; + ndbout << " activeCreat = " << tTcConptr.p->activeCreat + << " tcBlockref = " << hex << tTcConptr.p->tcBlockref + << " reqBlockref = " << hex << tTcConptr.p->reqBlockref + << " primKeyLen = " << tTcConptr.p->primKeyLen + << endl; + ndbout << " nextReplica = " << tTcConptr.p->nextReplica + << " tcBlockref = " << hex << tTcConptr.p->tcBlockref + << " reqBlockref = " << hex << tTcConptr.p->reqBlockref + << " primKeyLen = " << tTcConptr.p->primKeyLen + << endl; + ndbout << " logStopPageNo = " << tTcConptr.p->logStopPageNo + << " logStartPageNo = " << tTcConptr.p->logStartPageNo + << " logStartPageIndex = " << tTcConptr.p->logStartPageIndex + << endl; + ndbout << " errorCode = " << tTcConptr.p->errorCode + << " clientBlockref = " << hex << tTcConptr.p->clientBlockref + << " applRef = " << hex << tTcConptr.p->applRef + << " totSendlenAi = " << tTcConptr.p->totSendlenAi + << endl; + ndbout << " totReclenAi = " << tTcConptr.p->totReclenAi + << " tcScanRec = " << tTcConptr.p->tcScanRec + << " tcScanInfo = " << tTcConptr.p->tcScanInfo + << " tcOprec = " << hex << tTcConptr.p->tcOprec + << endl; + ndbout << " tableref = " << tTcConptr.p->tableref + << " simpleTcConnect = " << tTcConptr.p->simpleTcConnect + << " storedProcId = " << tTcConptr.p->storedProcId + << " schemaVersion = " << tTcConptr.p->schemaVersion + << endl; + ndbout << " reqinfo = " << tTcConptr.p->reqinfo + << " reqRef = " << tTcConptr.p->reqRef + << " readlenAi = " << tTcConptr.p->readlenAi + << " prevTc = " << tTcConptr.p->prevTc + << endl; + ndbout << " prevLogTcrec = " << tTcConptr.p->prevLogTcrec + << " prevHashRec = " << tTcConptr.p->prevHashRec + << " nodeAfterNext0 = " << tTcConptr.p->nodeAfterNext[0] + << " nodeAfterNext1 = " << tTcConptr.p->nodeAfterNext[1] + << endl; + ndbout << " nextTcConnectrec = " << tTcConptr.p->nextTcConnectrec + << " nextTc = " << tTcConptr.p->nextTc + << " nextTcLogQueue = " << tTcConptr.p->nextTcLogQueue + << " nextLogTcrec = " << tTcConptr.p->nextLogTcrec + << endl; + ndbout << " nextHashRec = " << tTcConptr.p->nextHashRec + << " logWriteState = " << tTcConptr.p->logWriteState + << " logStartFileNo = " << tTcConptr.p->logStartFileNo + << " listState = " << tTcConptr.p->listState + << endl; + ndbout << " lastAttrinbuf = " << tTcConptr.p->lastAttrinbuf + << " lastTupkeybuf = " << tTcConptr.p->lastTupkeybuf + << " hashValue = " << tTcConptr.p->hashValue + << endl; + ndbout << " gci = " << tTcConptr.p->gci + << " fragmentptr = " << tTcConptr.p->fragmentptr + << " fragmentid = " << tTcConptr.p->fragmentid + << " firstTupkeybuf = " << tTcConptr.p->firstTupkeybuf + << endl; + ndbout << " firstAttrinbuf = " << tTcConptr.p->firstAttrinbuf + << " currTupAiLen = " << tTcConptr.p->currTupAiLen + << " currReclenAi = " << tTcConptr.p->currReclenAi + << endl; + ndbout << " tcTimer = " << tTcConptr.p->tcTimer + << " clientConnectrec = " << tTcConptr.p->clientConnectrec + << " applOprec = " << hex << tTcConptr.p->applOprec + << " abortState = " << tTcConptr.p->abortState + << endl; + ndbout << " transid0 = " << hex << tTcConptr.p->transid[0] + << " transid1 = " << hex << tTcConptr.p->transid[1] + << " tupkeyData0 = " << tTcConptr.p->tupkeyData[0] + << " tupkeyData1 = " << tTcConptr.p->tupkeyData[1] + << endl; + ndbout << " tupkeyData2 = " << tTcConptr.p->tupkeyData[2] + << " tupkeyData3 = " << tTcConptr.p->tupkeyData[3] + << endl; + switch (tTcConptr.p->transactionState) { + + case TcConnectionrec::SCAN_STATE_USED: + if (tTcConptr.p->tcScanRec < cscanrecFileSize){ + ScanRecordPtr TscanPtr; + c_scanRecordPool.getPtr(TscanPtr, tTcConptr.p->tcScanRec); + ndbout << " scanState = " << TscanPtr.p->scanState << endl; + //TscanPtr.p->scanLocalref[2]; + ndbout << " copyPtr="<<TscanPtr.p->copyPtr + << " scanAccPtr="<<TscanPtr.p->scanAccPtr + << " scanAiLength="<<TscanPtr.p->scanAiLength + << endl; + ndbout << " m_curr_batch_size_rows="<< + TscanPtr.p->m_curr_batch_size_rows + << " m_max_batch_size_rows="<< + TscanPtr.p->m_max_batch_size_rows + << " scanErrorCounter="<<TscanPtr.p->scanErrorCounter + << " scanLocalFragid="<<TscanPtr.p->scanLocalFragid + << endl; + ndbout << " scanSchemaVersion="<<TscanPtr.p->scanSchemaVersion + << " scanStoredProcId="<<TscanPtr.p->scanStoredProcId + << " scanTcrec="<<TscanPtr.p->scanTcrec + << endl; + ndbout << " scanType="<<TscanPtr.p->scanType + << " scanApiBlockref="<<TscanPtr.p->scanApiBlockref + << " scanNodeId="<<TscanPtr.p->scanNodeId + << " scanCompletedStatus="<<TscanPtr.p->scanCompletedStatus + << endl; + ndbout << " scanFlag="<<TscanPtr.p->scanFlag + << " scanLockHold="<<TscanPtr.p->scanLockHold + << " scanLockMode="<<TscanPtr.p->scanLockMode + << " scanNumber="<<TscanPtr.p->scanNumber + << endl; + ndbout << " scanReleaseCounter="<<TscanPtr.p->scanReleaseCounter + << " scanTcWaiting="<<TscanPtr.p->scanTcWaiting + << " scanKeyinfoFlag="<<TscanPtr.p->scanKeyinfoFlag + << endl; + }else{ + ndbout << "No connected scan record found" << endl; + } + break; + default: + break; + }//switch + + // Reset the timer + tTcConptr.p->tcTimer = 0; + }//if + }//for +#endif +#ifdef VM_TRACE + for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) { + ptrAss(lfoPtr, logFileOperationRecord); + if ((lfoPtr.p->lfoTimer != 0) && + ((lfoPtr.p->lfoTimer + 120) < cLqhTimeOutCount)) { + ndbout << "We have lost LFO record" << endl; + ndbout << "index = " << lfoPtr.i; + ndbout << "State = " << lfoPtr.p->lfoState; + ndbout << " Page No = " << lfoPtr.p->lfoPageNo; + ndbout << " noPagesRw = " << lfoPtr.p->noPagesRw; + ndbout << "lfoWordWritten = " << lfoPtr.p->lfoWordWritten << endl; + lfoPtr.p->lfoTimer = cLqhTimeOutCount; + }//if + }//for + +#endif + +#if 0 + LcpRecordPtr TlcpPtr; + // Print information about the current local checkpoint + TlcpPtr.i = 0; + ptrAss(TlcpPtr, lcpRecord); + ndbout << "Information about LCP in this LQH" << endl + << " lcpState="<<TlcpPtr.p->lcpState<<endl + << " firstLcpLocAcc="<<TlcpPtr.p->firstLcpLocAcc<<endl + << " firstLcpLocTup="<<TlcpPtr.p->firstLcpLocTup<<endl + << " lcpAccptr="<<TlcpPtr.p->lcpAccptr<<endl + << " lastFragmentFlag="<<TlcpPtr.p->lastFragmentFlag<<endl + << " lcpQueued="<<TlcpPtr.p->lcpQueued<<endl + << " reportEmptyref="<< TlcpPtr.p->reportEmptyRef<<endl + << " reportEmpty="<<TlcpPtr.p->reportEmpty<<endl; +#endif +}//Dblqh::execTIME_SIGNAL() + +/* ######################################################################### */ +/* ####### EXECUTION MODULE ####### */ +/* THIS MODULE HANDLES THE RECEPTION OF LQHKEYREQ AND ALL PROCESSING */ +/* OF OPERATIONS ON BEHALF OF THIS REQUEST. THIS DOES ALSO INVOLVE */ +/* RECEPTION OF VARIOUS TYPES OF ATTRINFO AND KEYINFO. IT DOES ALSO */ +/* INVOLVE COMMUNICATION WITH ACC AND TUP. */ +/* ######################################################################### */ + +void Dblqh::noFreeRecordLab(Signal* signal, + const LqhKeyReq * lqhKeyReq, + Uint32 errCode) +{ + jamEntry(); + const Uint32 transid1 = lqhKeyReq->transId1; + const Uint32 transid2 = lqhKeyReq->transId2; + const Uint32 reqInfo = lqhKeyReq->requestInfo; + + if(errCode == ZNO_FREE_MARKER_RECORDS_ERROR || + errCode == ZNODE_SHUTDOWN_IN_PROGESS){ + releaseTcrec(signal, tcConnectptr); + } + + if (LqhKeyReq::getSimpleFlag(reqInfo) && + LqhKeyReq::getOperation(reqInfo) == ZREAD){ + jam(); + ndbrequire(LqhKeyReq::getApplicationAddressFlag(reqInfo)); + const Uint32 apiRef = lqhKeyReq->variableData[0]; + const Uint32 apiOpRec = lqhKeyReq->variableData[1]; + + TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); + + tcKeyRef->connectPtr = apiOpRec; + tcKeyRef->transId[0] = transid1; + tcKeyRef->transId[1] = transid2; + tcKeyRef->errorCode = errCode; + sendSignal(apiRef, GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); + } else { + jam(); + + const Uint32 clientPtr = lqhKeyReq->clientConnectPtr; + Uint32 TcOprec = clientPtr; + if(LqhKeyReq::getSameClientAndTcFlag(reqInfo) == 1){ + if(LqhKeyReq::getApplicationAddressFlag(reqInfo)) + TcOprec = lqhKeyReq->variableData[2]; + else + TcOprec = lqhKeyReq->variableData[0]; + } + + LqhKeyRef * const ref = (LqhKeyRef*)signal->getDataPtrSend(); + ref->userRef = clientPtr; + ref->connectPtr = TcOprec; + ref->errorCode = errCode; + ref->transId1 = transid1; + ref->transId2 = transid2; + sendSignal(signal->senderBlockRef(), GSN_LQHKEYREF, signal, + LqhKeyRef::SignalLength, JBB); + }//if + return; +}//Dblqh::noFreeRecordLab() + +void Dblqh::LQHKEY_abort(Signal* signal, int errortype) +{ + switch (errortype) { + case 0: + jam(); + terrorCode = ZCOPY_NODE_ERROR; + break; + case 1: + jam(); + terrorCode = ZNO_FREE_LQH_CONNECTION; + break; + case 2: + jam(); + terrorCode = signal->theData[1]; + break; + case 3: + jam(); + ndbrequire((tcConnectptr.p->transactionState == TcConnectionrec::WAIT_ACC_ABORT) || + (tcConnectptr.p->transactionState == TcConnectionrec::ABORT_STOPPED) || + (tcConnectptr.p->transactionState == TcConnectionrec::ABORT_QUEUED)); + return; + break; + case 4: + jam(); + if(tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ + jam(); + terrorCode = ZTABLE_NOT_DEFINED; + } else if (tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || + tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ + jam(); + terrorCode = ZDROP_TABLE_IN_PROGRESS; + } else { + ndbrequire(0); + } + break; + case 5: + jam(); + terrorCode = ZINVALID_SCHEMA_VERSION; + break; + default: + ndbrequire(false); + break; + }//switch + abortErrorLab(signal); +}//Dblqh::LQHKEY_abort() + +void Dblqh::LQHKEY_error(Signal* signal, int errortype) +{ + switch (errortype) { + case 0: + jam(); + break; + case 1: + jam(); + break; + case 2: + jam(); + break; + case 3: + jam(); + break; + case 4: + jam(); + break; + case 5: + jam(); + break; + case 6: + jam(); + break; + default: + jam(); + break; + }//switch + ndbrequire(false); +}//Dblqh::LQHKEY_error() + +void Dblqh::execLQHKEYREF(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + terrorCode = signal->theData[2]; + Uint32 transid1 = signal->theData[3]; + Uint32 transid2 = signal->theData[4]; + if (tcConnectptr.i >= ctcConnectrecFileSize) { + errorReport(signal, 3); + return; + }//if +/*------------------------------------------------------------------*/ +/* WE HAVE TO CHECK THAT THE SIGNAL DO NOT BELONG TO SOMETHING*/ +/* REMOVED DUE TO A TIME-OUT. */ +/*------------------------------------------------------------------*/ + ptrAss(tcConnectptr, tcConnectionrec); + TcConnectionrec * const regTcPtr = tcConnectptr.p; + switch (regTcPtr->connectState) { + case TcConnectionrec::CONNECTED: + jam(); + if ((regTcPtr->transid[0] != transid1) || + (regTcPtr->transid[1] != transid2)) { + warningReport(signal, 14); + return; + }//if + if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { + warningReport(signal, 15); + return; + }//if + abortErrorLab(signal); + return; + break; + case TcConnectionrec::LOG_CONNECTED: + jam(); + logLqhkeyrefLab(signal); + return; + break; + case TcConnectionrec::COPY_CONNECTED: + jam(); + copyLqhKeyRefLab(signal); + return; + break; + default: + warningReport(signal, 16); + return; + break; + }//switch +}//Dblqh::execLQHKEYREF() + +/* -------------------------------------------------------------------------- */ +/* ------- ENTER PACKED_SIGNAL ------- */ +/* Execution of packed signal. The packed signal can contain COMMIT, COMPLETE */ +/* or LQHKEYCONF signals. These signals will be executed by their resp. exec */ +/* functions. */ +/* -------------------------------------------------------------------------- */ +void Dblqh::execPACKED_SIGNAL(Signal* signal) +{ + Uint32 Tstep = 0; + Uint32 Tlength; + Uint32 TpackedData[28]; + Uint32 sig0, sig1, sig2, sig3 ,sig4, sig5, sig6; + + jamEntry(); + Tlength = signal->length(); + ndbrequire(Tlength <= 25); + MEMCOPY_NO_WORDS(&TpackedData[0], &signal->theData[0], Tlength); + while (Tlength > Tstep) { + switch (TpackedData[Tstep] >> 28) { + case ZCOMMIT: + jam(); + sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; + sig1 = TpackedData[Tstep + 1]; + sig2 = TpackedData[Tstep + 2]; + sig3 = TpackedData[Tstep + 3]; + signal->theData[0] = sig0; + signal->theData[1] = sig1; + signal->theData[2] = sig2; + signal->theData[3] = sig3; + signal->header.theLength = 4; + execCOMMIT(signal); + Tstep += 4; + break; + case ZCOMPLETE: + jam(); + sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; + sig1 = TpackedData[Tstep + 1]; + sig2 = TpackedData[Tstep + 2]; + signal->theData[0] = sig0; + signal->theData[1] = sig1; + signal->theData[2] = sig2; + signal->header.theLength = 3; + execCOMPLETE(signal); + Tstep += 3; + break; + case ZLQHKEYCONF: { + jam(); + LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); + + sig0 = TpackedData[Tstep + 0] & 0x0FFFFFFF; + sig1 = TpackedData[Tstep + 1]; + sig2 = TpackedData[Tstep + 2]; + sig3 = TpackedData[Tstep + 3]; + sig4 = TpackedData[Tstep + 4]; + sig5 = TpackedData[Tstep + 5]; + sig6 = TpackedData[Tstep + 6]; + lqhKeyConf->connectPtr = sig0; + lqhKeyConf->opPtr = sig1; + lqhKeyConf->userRef = sig2; + lqhKeyConf->readLen = sig3; + lqhKeyConf->transId1 = sig4; + lqhKeyConf->transId2 = sig5; + lqhKeyConf->noFiredTriggers = sig6; + execLQHKEYCONF(signal); + Tstep += LqhKeyConf::SignalLength; + break; + } + case ZREMOVE_MARKER: + jam(); + sig0 = TpackedData[Tstep + 1]; + sig1 = TpackedData[Tstep + 2]; + signal->theData[0] = sig0; + signal->theData[1] = sig1; + signal->header.theLength = 2; + execREMOVE_MARKER_ORD(signal); + Tstep += 3; + break; + default: + ndbrequire(false); + return; + }//switch + }//while + ndbrequire(Tlength == Tstep); + return; +}//Dblqh::execPACKED_SIGNAL() + +void +Dblqh::execREMOVE_MARKER_ORD(Signal* signal) +{ + CommitAckMarker key; + key.transid1 = signal->theData[0]; + key.transid2 = signal->theData[1]; + jamEntry(); + + CommitAckMarkerPtr removedPtr; + m_commitAckMarkerHash.release(removedPtr, key); + ndbrequire(removedPtr.i != RNIL); +#ifdef MARKER_TRACE + ndbout_c("Rem marker[%.8x %.8x]", key.transid1, key.transid2); +#endif +} + + +/* -------------------------------------------------------------------------- */ +/* ------- ENTER SEND_PACKED ------- */ +/* Used to force a packed signal to be sent if local signal buffer is not */ +/* empty. */ +/* -------------------------------------------------------------------------- */ +void Dblqh::execSEND_PACKED(Signal* signal) +{ + HostRecordPtr Thostptr; + UintR i; + UintR TpackedListIndex = cpackedListIndex; + jamEntry(); + for (i = 0; i < TpackedListIndex; i++) { + Thostptr.i = cpackedList[i]; + ptrAss(Thostptr, hostRecord); + jam(); + ndbrequire(Thostptr.i - 1 < MAX_NDB_NODES - 1); + if (Thostptr.p->noOfPackedWordsLqh > 0) { + jam(); + sendPackedSignalLqh(signal, Thostptr.p); + }//if + if (Thostptr.p->noOfPackedWordsTc > 0) { + jam(); + sendPackedSignalTc(signal, Thostptr.p); + }//if + Thostptr.p->inPackedList = false; + }//for + cpackedListIndex = 0; + return; +}//Dblqh::execSEND_PACKED() + +void +Dblqh::updatePackedList(Signal* signal, HostRecord * ahostptr, Uint16 hostId) +{ + Uint32 TpackedListIndex = cpackedListIndex; + if (ahostptr->inPackedList == false) { + jam(); + ahostptr->inPackedList = true; + cpackedList[TpackedListIndex] = hostId; + cpackedListIndex = TpackedListIndex + 1; + }//if +}//Dblqh::updatePackedList() + +void +Dblqh::execREAD_PSUEDO_REQ(Signal* signal){ + jamEntry(); + TcConnectionrecPtr regTcPtr; + regTcPtr.i = signal->theData[0]; + ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec); + + if(signal->theData[1] != AttributeHeader::RANGE_NO) + { + jam(); + FragrecordPtr regFragptr; + regFragptr.i = regTcPtr.p->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + + signal->theData[0] = regFragptr.p->accFragptr[regTcPtr.p->localFragptr]; + EXECUTE_DIRECT(DBACC, GSN_READ_PSUEDO_REQ, signal, 2); + } + else + { + signal->theData[0] = regTcPtr.p->m_scan_curr_range_no; + } +} + +/* ************>> */ +/* 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); + switch (tcConnectptr.p->transactionState) { + case TcConnectionrec::WAIT_TUP: + jam(); + if (tcConnectptr.p->seqNoReplica == 0) // Primary replica + tcConnectptr.p->noFiredTriggers = tupKeyConf->noFiredTriggers; + tupkeyConfLab(signal); + break; + case TcConnectionrec::COPY_TUPKEY: + jam(); + copyTupkeyConfLab(signal); + break; + case TcConnectionrec::SCAN_TUPKEY: + jam(); + scanTupkeyConfLab(signal); + break; + case TcConnectionrec::WAIT_TUP_TO_ABORT: + jam(); +/* ------------------------------------------------------------------------- */ +// Abort was not ready to start until this signal came back. Now we are ready +// to start the abort. +/* ------------------------------------------------------------------------- */ + releaseActiveFrag(signal); + abortCommonLab(signal); + break; + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::ABORT_QUEUED: + jam(); +/* -------------------------------------------------------------------------- */ +/* IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ +/* -------------------------------------------------------------------------- */ + break; + default: + ndbrequire(false); + break; + }//switch +}//Dblqh::execTUPKEYCONF() + +/* ************> */ +/* TUPKEYREF > */ +/* ************> */ +void Dblqh::execTUPKEYREF(Signal* signal) +{ + const TupKeyRef * const tupKeyRef = (TupKeyRef *)signal->getDataPtr(); + + jamEntry(); + tcConnectptr.i = tupKeyRef->userRef; + terrorCode = tupKeyRef->errorCode; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + switch (tcConnectptr.p->transactionState) { + case TcConnectionrec::WAIT_TUP: + jam(); + releaseActiveFrag(signal); + abortErrorLab(signal); + break; + case TcConnectionrec::COPY_TUPKEY: + ndbrequire(false); + break; + case TcConnectionrec::SCAN_TUPKEY: + jam(); + scanTupkeyRefLab(signal); + break; + case TcConnectionrec::WAIT_TUP_TO_ABORT: + jam(); +/* ------------------------------------------------------------------------- */ +// Abort was not ready to start until this signal came back. Now we are ready +// to start the abort. +/* ------------------------------------------------------------------------- */ + releaseActiveFrag(signal); + abortCommonLab(signal); + break; + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::ABORT_QUEUED: + jam(); +/* ------------------------------------------------------------------------- */ +/* IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ +/* ------------------------------------------------------------------------- */ + break; + default: + ndbrequire(false); + break; + }//switch +}//Dblqh::execTUPKEYREF() + +void Dblqh::sendPackedSignalLqh(Signal* signal, HostRecord * ahostptr) +{ + Uint32 noOfWords = ahostptr->noOfPackedWordsLqh; + BlockReference hostRef = ahostptr->hostLqhBlockRef; + MEMCOPY_NO_WORDS(&signal->theData[0], + &ahostptr->packedWordsLqh[0], + noOfWords); + sendSignal(hostRef, GSN_PACKED_SIGNAL, signal, noOfWords, JBB); + ahostptr->noOfPackedWordsLqh = 0; +}//Dblqh::sendPackedSignalLqh() + +void Dblqh::sendPackedSignalTc(Signal* signal, HostRecord * ahostptr) +{ + Uint32 noOfWords = ahostptr->noOfPackedWordsTc; + BlockReference hostRef = ahostptr->hostTcBlockRef; + MEMCOPY_NO_WORDS(&signal->theData[0], + &ahostptr->packedWordsTc[0], + noOfWords); + sendSignal(hostRef, GSN_PACKED_SIGNAL, signal, noOfWords, JBB); + ahostptr->noOfPackedWordsTc = 0; +}//Dblqh::sendPackedSignalTc() + +void Dblqh::sendCommitLqh(Signal* signal, BlockReference alqhBlockref) +{ + HostRecordPtr Thostptr; + Thostptr.i = refToNode(alqhBlockref); + ptrCheckGuard(Thostptr, chostFileSize, hostRecord); + if (Thostptr.p->noOfPackedWordsLqh > 21) { + jam(); + sendPackedSignalLqh(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + Uint32 pos = Thostptr.p->noOfPackedWordsLqh; + Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMMIT << 28); + Uint32 gci = tcConnectptr.p->gci; + Uint32 transid1 = tcConnectptr.p->transid[0]; + Uint32 transid2 = tcConnectptr.p->transid[1]; + Thostptr.p->packedWordsLqh[pos] = ptrAndType; + Thostptr.p->packedWordsLqh[pos + 1] = gci; + Thostptr.p->packedWordsLqh[pos + 2] = transid1; + Thostptr.p->packedWordsLqh[pos + 3] = transid2; + Thostptr.p->noOfPackedWordsLqh = pos + 4; +}//Dblqh::sendCommitLqh() + +void Dblqh::sendCompleteLqh(Signal* signal, BlockReference alqhBlockref) +{ + HostRecordPtr Thostptr; + Thostptr.i = refToNode(alqhBlockref); + ptrCheckGuard(Thostptr, chostFileSize, hostRecord); + if (Thostptr.p->noOfPackedWordsLqh > 22) { + jam(); + sendPackedSignalLqh(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + Uint32 pos = Thostptr.p->noOfPackedWordsLqh; + Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMPLETE << 28); + Uint32 transid1 = tcConnectptr.p->transid[0]; + Uint32 transid2 = tcConnectptr.p->transid[1]; + Thostptr.p->packedWordsLqh[pos] = ptrAndType; + Thostptr.p->packedWordsLqh[pos + 1] = transid1; + Thostptr.p->packedWordsLqh[pos + 2] = transid2; + Thostptr.p->noOfPackedWordsLqh = pos + 3; +}//Dblqh::sendCompleteLqh() + +void Dblqh::sendCommittedTc(Signal* signal, BlockReference atcBlockref) +{ + HostRecordPtr Thostptr; + Thostptr.i = refToNode(atcBlockref); + ptrCheckGuard(Thostptr, chostFileSize, hostRecord); + if (Thostptr.p->noOfPackedWordsTc > 22) { + jam(); + sendPackedSignalTc(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + Uint32 pos = Thostptr.p->noOfPackedWordsTc; + Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMMITTED << 28); + Uint32 transid1 = tcConnectptr.p->transid[0]; + Uint32 transid2 = tcConnectptr.p->transid[1]; + Thostptr.p->packedWordsTc[pos] = ptrAndType; + Thostptr.p->packedWordsTc[pos + 1] = transid1; + Thostptr.p->packedWordsTc[pos + 2] = transid2; + Thostptr.p->noOfPackedWordsTc = pos + 3; +}//Dblqh::sendCommittedTc() + +void Dblqh::sendCompletedTc(Signal* signal, BlockReference atcBlockref) +{ + HostRecordPtr Thostptr; + Thostptr.i = refToNode(atcBlockref); + ptrCheckGuard(Thostptr, chostFileSize, hostRecord); + if (Thostptr.p->noOfPackedWordsTc > 22) { + jam(); + sendPackedSignalTc(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + Uint32 pos = Thostptr.p->noOfPackedWordsTc; + Uint32 ptrAndType = tcConnectptr.p->clientConnectrec | (ZCOMPLETED << 28); + Uint32 transid1 = tcConnectptr.p->transid[0]; + Uint32 transid2 = tcConnectptr.p->transid[1]; + Thostptr.p->packedWordsTc[pos] = ptrAndType; + Thostptr.p->packedWordsTc[pos + 1] = transid1; + Thostptr.p->packedWordsTc[pos + 2] = transid2; + Thostptr.p->noOfPackedWordsTc = pos + 3; +}//Dblqh::sendCompletedTc() + +void Dblqh::sendLqhkeyconfTc(Signal* signal, BlockReference atcBlockref) +{ + LqhKeyConf* lqhKeyConf; + HostRecordPtr Thostptr; + + Thostptr.i = refToNode(atcBlockref); + ptrCheckGuard(Thostptr, chostFileSize, hostRecord); + if (refToBlock(atcBlockref) == DBTC) { + jam(); +/******************************************************************* +// This signal was intended for DBTC as part of the normal transaction +// execution. +********************************************************************/ + if (Thostptr.p->noOfPackedWordsTc > (25 - LqhKeyConf::SignalLength)) { + jam(); + sendPackedSignalTc(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + lqhKeyConf = (LqhKeyConf *) + &Thostptr.p->packedWordsTc[Thostptr.p->noOfPackedWordsTc]; + Thostptr.p->noOfPackedWordsTc += LqhKeyConf::SignalLength; + } else { + jam(); +/******************************************************************* +// This signal was intended for DBLQH as part of log execution or +// node recovery. +********************************************************************/ + if (Thostptr.p->noOfPackedWordsLqh > (25 - LqhKeyConf::SignalLength)) { + jam(); + sendPackedSignalLqh(signal, Thostptr.p); + } else { + jam(); + updatePackedList(signal, Thostptr.p, Thostptr.i); + }//if + lqhKeyConf = (LqhKeyConf *) + &Thostptr.p->packedWordsLqh[Thostptr.p->noOfPackedWordsLqh]; + Thostptr.p->noOfPackedWordsLqh += LqhKeyConf::SignalLength; + }//if + Uint32 ptrAndType = tcConnectptr.i | (ZLQHKEYCONF << 28); + Uint32 tcOprec = tcConnectptr.p->tcOprec; + Uint32 ownRef = cownref; + Uint32 readlenAi = tcConnectptr.p->readlenAi; + Uint32 transid1 = tcConnectptr.p->transid[0]; + Uint32 transid2 = tcConnectptr.p->transid[1]; + Uint32 noFiredTriggers = tcConnectptr.p->noFiredTriggers; + lqhKeyConf->connectPtr = ptrAndType; + lqhKeyConf->opPtr = tcOprec; + lqhKeyConf->userRef = ownRef; + lqhKeyConf->readLen = readlenAi; + lqhKeyConf->transId1 = transid1; + lqhKeyConf->transId2 = transid2; + lqhKeyConf->noFiredTriggers = noFiredTriggers; +}//Dblqh::sendLqhkeyconfTc() + +/* ************************************************************************>> + * KEYINFO: Get tuple request from DBTC. Next step is to contact DBACC to get + * key to tuple if all key/attrinfo has been received, else for more attrinfo + * signals. + * ************************************************************************>> */ +void Dblqh::execKEYINFO(Signal* signal) +{ + Uint32 tcOprec = signal->theData[0]; + Uint32 transid1 = signal->theData[1]; + Uint32 transid2 = signal->theData[2]; + jamEntry(); + if (findTransaction(transid1, transid2, tcOprec) != ZOK) { + jam(); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + TcConnectionrec::TransactionState state = regTcPtr->transactionState; + if (state != TcConnectionrec::WAIT_TUPKEYINFO && + state != TcConnectionrec::WAIT_SCAN_AI) + { + jam(); +/*****************************************************************************/ +/* TRANSACTION WAS ABORTED, THIS IS MOST LIKELY A SIGNAL BELONGING TO THE */ +/* ABORTED TRANSACTION. THUS IGNORE THE SIGNAL. */ +/*****************************************************************************/ + return; + }//if + Uint32 errorCode = handleLongTupKey(signal, + (Uint32)regTcPtr->save1, + (Uint32)regTcPtr->primKeyLen, + &signal->theData[3]); + if (errorCode != 0) { + if (errorCode == 1) { + jam(); + return; + }//if + jam(); + terrorCode = errorCode; + if(state == TcConnectionrec::WAIT_TUPKEYINFO) + abortErrorLab(signal); + else + abort_scan(signal, regTcPtr->tcScanRec, errorCode); + return; + }//if + if(state == TcConnectionrec::WAIT_TUPKEYINFO) + { + FragrecordPtr regFragptr; + regFragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + fragptr = regFragptr; + endgettupkeyLab(signal); + } + return; +}//Dblqh::execKEYINFO() + +/* ------------------------------------------------------------------------- */ +/* FILL IN KEY DATA INTO DATA BUFFERS. */ +/* ------------------------------------------------------------------------- */ +Uint32 Dblqh::handleLongTupKey(Signal* signal, + Uint32 keyLength, + Uint32 primKeyLength, + Uint32* dataPtr) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 dataPos = 0; + while (true) { + keyLength += 4; + if (cfirstfreeDatabuf == RNIL) { + jam(); + return ZGET_DATAREC_ERROR; + }//if + seizeTupkeybuf(signal); + Databuf * const regDataPtr = databufptr.p; + Uint32 data0 = dataPtr[dataPos]; + Uint32 data1 = dataPtr[dataPos + 1]; + Uint32 data2 = dataPtr[dataPos + 2]; + Uint32 data3 = dataPtr[dataPos + 3]; + regDataPtr->data[0] = data0; + regDataPtr->data[1] = data1; + regDataPtr->data[2] = data2; + regDataPtr->data[3] = data3; + dataPos += 4; + if (keyLength < primKeyLength) { + if (dataPos > 16) { + jam(); +/* SAVE STATE AND WAIT FOR KEYINFO */ + regTcPtr->save1 = keyLength; + return 1; + }//if + } else { + jam(); + return 0; + }//if + }//while +}//Dblqh::handleLongTupKey() + +/* ------------------------------------------------------------------------- */ +/* ------- HANDLE ATTRINFO SIGNALS ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +/* ************************************************************************>> */ +/* ATTRINFO: Continuation of KEYINFO signal (except for scans that do not use*/ +/* any KEYINFO). When all key and attribute info is received we contact DBACC*/ +/* for index handling. */ +/* ************************************************************************>> */ +void Dblqh::execATTRINFO(Signal* signal) +{ + Uint32 tcOprec = signal->theData[0]; + Uint32 transid1 = signal->theData[1]; + Uint32 transid2 = signal->theData[2]; + jamEntry(); + if (findTransaction(transid1, + transid2, + tcOprec) != ZOK) { + jam(); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 length = signal->length() - 3; + Uint32 totReclenAi = regTcPtr->totReclenAi; + Uint32 currReclenAi = regTcPtr->currReclenAi + length; + Uint32* dataPtr = &signal->theData[3]; + regTcPtr->currReclenAi = currReclenAi; + if (totReclenAi == currReclenAi) { + switch (regTcPtr->transactionState) { + case TcConnectionrec::WAIT_ATTR: + { + Fragrecord *regFragrecord = fragrecord; + Uint32 fragIndex = regTcPtr->fragmentptr; + Uint32 tfragrecFileSize = cfragrecFileSize; + jam(); + fragptr.i = fragIndex; + ptrCheckGuard(fragptr, tfragrecFileSize, regFragrecord); + lqhAttrinfoLab(signal, dataPtr, length); + endgettupkeyLab(signal); + return; + break; + } + case TcConnectionrec::WAIT_SCAN_AI: + jam(); + scanAttrinfoLab(signal, dataPtr, length); + return; + break; + case TcConnectionrec::WAIT_TUP_TO_ABORT: + case TcConnectionrec::LOG_ABORT_QUEUED: + case TcConnectionrec::ABORT_QUEUED: + case TcConnectionrec::ABORT_STOPPED: + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::WAIT_AI_AFTER_ABORT: + jam(); + aiStateErrorCheckLab(signal, dataPtr,length); + return; + break; + default: + jam(); + ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE); + break; + }//switch + } else if (currReclenAi < totReclenAi) { + jam(); + switch (regTcPtr->transactionState) { + case TcConnectionrec::WAIT_ATTR: + jam(); + lqhAttrinfoLab(signal, dataPtr, length); + return; + break; + case TcConnectionrec::WAIT_SCAN_AI: + jam(); + scanAttrinfoLab(signal, dataPtr, length); + return; + break; + case TcConnectionrec::WAIT_TUP_TO_ABORT: + case TcConnectionrec::LOG_ABORT_QUEUED: + case TcConnectionrec::ABORT_QUEUED: + case TcConnectionrec::ABORT_STOPPED: + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::WAIT_AI_AFTER_ABORT: + jam(); + aiStateErrorCheckLab(signal, dataPtr, length); + return; + break; + default: + jam(); + ndbrequire(regTcPtr->abortState != TcConnectionrec::ABORT_IDLE); + break; + }//switch + } else { + switch (regTcPtr->transactionState) { + case TcConnectionrec::WAIT_SCAN_AI: + jam(); + scanAttrinfoLab(signal, dataPtr, length); + return; + break; + default: + ndbout_c("%d", regTcPtr->transactionState); + ndbrequire(false); + break; + }//switch + }//if + return; +}//Dblqh::execATTRINFO() + +/* ************************************************************************>> */ +/* TUP_ATTRINFO: Interpreted execution in DBTUP generates redo-log info */ +/* which is sent back to DBLQH for logging. This is because the decision */ +/* to execute or not is made in DBTUP and thus we cannot start logging until */ +/* DBTUP part has been run. */ +/* ************************************************************************>> */ +void Dblqh::execTUP_ATTRINFO(Signal* signal) +{ + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + Uint32 length = signal->length() - 3; + Uint32 tcIndex = signal->theData[0]; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + jamEntry(); + tcConnectptr.i = tcIndex; + ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); + ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::WAIT_TUP); + if (saveTupattrbuf(signal, &signal->theData[3], length) == ZOK) { + return; + } else { + jam(); +/* ------------------------------------------------------------------------- */ +/* WE ARE WAITING FOR RESPONSE FROM TUP HERE. THUS WE NEED TO */ +/* GO THROUGH THE STATE MACHINE FOR THE OPERATION. */ +/* ------------------------------------------------------------------------- */ + localAbortStateHandlerLab(signal); + }//if +}//Dblqh::execTUP_ATTRINFO() + +/* ------------------------------------------------------------------------- */ +/* ------- HANDLE ATTRINFO FROM LQH ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::lqhAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->operation != ZREAD) { + if (regTcPtr->opExec != 1) { + if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { + ; + } else { + jam(); +/* ------------------------------------------------------------------------- */ +/* WE MIGHT BE WAITING FOR RESPONSE FROM SOME BLOCK HERE. THUS WE NEED TO */ +/* GO THROUGH THE STATE MACHINE FOR THE OPERATION. */ +/* ------------------------------------------------------------------------- */ + localAbortStateHandlerLab(signal); + return; + }//if + }//if + }//if + Uint32 sig0 = regTcPtr->tupConnectrec; + Uint32 blockNo = refToBlock(regTcPtr->tcTupBlockref); + signal->theData[0] = sig0; + EXECUTE_DIRECT(blockNo, GSN_ATTRINFO, signal, length + 3); + jamEntry(); +}//Dblqh::lqhAttrinfoLab() + +/* ------------------------------------------------------------------------- */ +/* ------ FIND TRANSACTION BY USING HASH TABLE ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +int Dblqh::findTransaction(UintR Transid1, UintR Transid2, UintR TcOprec) +{ + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + TcConnectionrecPtr locTcConnectptr; + + Uint32 ThashIndex = (Transid1 ^ TcOprec) & 1023; + locTcConnectptr.i = ctransidHash[ThashIndex]; + while (locTcConnectptr.i != RNIL) { + ptrCheckGuard(locTcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); + if ((locTcConnectptr.p->transid[0] == Transid1) && + (locTcConnectptr.p->transid[1] == Transid2) && + (locTcConnectptr.p->tcOprec == TcOprec)) { +/* FIRST PART OF TRANSACTION CORRECT */ +/* SECOND PART ALSO CORRECT */ +/* THE OPERATION RECORD POINTER IN TC WAS ALSO CORRECT */ + jam(); + tcConnectptr.i = locTcConnectptr.i; + tcConnectptr.p = locTcConnectptr.p; + return (int)ZOK; + }//if + jam(); +/* THIS WAS NOT THE TRANSACTION WHICH WAS SOUGHT */ + locTcConnectptr.i = locTcConnectptr.p->nextHashRec; + }//while +/* WE DID NOT FIND THE TRANSACTION, REPORT NOT FOUND */ + return (int)ZNOT_FOUND; +}//Dblqh::findTransaction() + +/* ------------------------------------------------------------------------- */ +/* ------- SAVE ATTRINFO FROM TUP IN ATTRINBUF ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +int Dblqh::saveTupattrbuf(Signal* signal, Uint32* dataPtr, Uint32 length) +{ + Uint32 tfirstfreeAttrinbuf = cfirstfreeAttrinbuf; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 currTupAiLen = regTcPtr->currTupAiLen; + if (tfirstfreeAttrinbuf == RNIL) { + jam(); + terrorCode = ZGET_ATTRINBUF_ERROR; + return ZGET_ATTRINBUF_ERROR; + }//if + seizeAttrinbuf(signal); + Attrbuf * const regAttrPtr = attrinbufptr.p; + MEMCOPY_NO_WORDS(®AttrPtr->attrbuf[0], dataPtr, length); + regTcPtr->currTupAiLen = currTupAiLen + length; + regAttrPtr->attrbuf[ZINBUF_DATA_LEN] = length; + return ZOK; +}//Dblqh::saveTupattrbuf() + +/* ========================================================================== + * ======= SEIZE ATTRIBUTE IN BUFFER ======= + * + * GET A NEW ATTRINBUF AND SETS ATTRINBUFPTR. + * ========================================================================= */ +void Dblqh::seizeAttrinbuf(Signal* signal) +{ + AttrbufPtr tmpAttrinbufptr; + AttrbufPtr regAttrinbufptr; + Attrbuf *regAttrbuf = attrbuf; + Uint32 tattrinbufFileSize = cattrinbufFileSize; + + regAttrinbufptr.i = seize_attrinbuf(); + tmpAttrinbufptr.i = tcConnectptr.p->lastAttrinbuf; + ptrCheckGuard(regAttrinbufptr, tattrinbufFileSize, regAttrbuf); + tcConnectptr.p->lastAttrinbuf = regAttrinbufptr.i; + regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN] = 0; + if (tmpAttrinbufptr.i == RNIL) { + jam(); + tcConnectptr.p->firstAttrinbuf = regAttrinbufptr.i; + } else { + jam(); + ptrCheckGuard(tmpAttrinbufptr, tattrinbufFileSize, regAttrbuf); + tmpAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = regAttrinbufptr.i; + }//if + regAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL; + attrinbufptr = regAttrinbufptr; +}//Dblqh::seizeAttrinbuf() + +/* ========================================================================== + * ======= SEIZE TC CONNECT RECORD ======= + * + * GETS A NEW TC CONNECT RECORD FROM FREELIST. + * ========================================================================= */ +void Dblqh::seizeTcrec() +{ + TcConnectionrecPtr locTcConnectptr; + + locTcConnectptr.i = cfirstfreeTcConrec; + ptrCheckGuard(locTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + Uint32 nextTc = locTcConnectptr.p->nextTcConnectrec; + locTcConnectptr.p->nextTcConnectrec = RNIL; + locTcConnectptr.p->clientConnectrec = RNIL; + locTcConnectptr.p->clientBlockref = RNIL; + locTcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; + locTcConnectptr.p->tcTimer = cLqhTimeOutCount; + locTcConnectptr.p->tableref = RNIL; + locTcConnectptr.p->savePointId = 0; + cfirstfreeTcConrec = nextTc; + tcConnectptr = locTcConnectptr; + locTcConnectptr.p->connectState = TcConnectionrec::CONNECTED; +}//Dblqh::seizeTcrec() + +/* ========================================================================== + * ======= SEIZE DATA BUFFER ======= + * ========================================================================= */ +void Dblqh::seizeTupkeybuf(Signal* signal) +{ + Databuf *regDatabuf = databuf; + DatabufPtr tmpDatabufptr; + DatabufPtr regDatabufptr; + Uint32 tdatabufFileSize = cdatabufFileSize; + +/* ------- GET A DATABUF. ------- */ + regDatabufptr.i = cfirstfreeDatabuf; + tmpDatabufptr.i = tcConnectptr.p->lastTupkeybuf; + ptrCheckGuard(regDatabufptr, tdatabufFileSize, regDatabuf); + Uint32 nextFirst = regDatabufptr.p->nextDatabuf; + tcConnectptr.p->lastTupkeybuf = regDatabufptr.i; + if (tmpDatabufptr.i == RNIL) { + jam(); + tcConnectptr.p->firstTupkeybuf = regDatabufptr.i; + } else { + jam(); + ptrCheckGuard(tmpDatabufptr, tdatabufFileSize, regDatabuf); + tmpDatabufptr.p->nextDatabuf = regDatabufptr.i; + }//if + cfirstfreeDatabuf = nextFirst; + regDatabufptr.p->nextDatabuf = RNIL; + databufptr = regDatabufptr; +}//Dblqh::seizeTupkeybuf() + +/* ------------------------------------------------------------------------- */ +/* ------- TAKE CARE OF LQHKEYREQ ------- */ +/* LQHKEYREQ IS THE SIGNAL THAT STARTS ALL OPERATIONS IN THE LQH BLOCK */ +/* THIS SIGNAL CONTAINS A LOT OF INFORMATION ABOUT WHAT TYPE OF OPERATION, */ +/* KEY INFORMATION, ATTRIBUTE INFORMATION, NODE INFORMATION AND A LOT MORE */ +/* ------------------------------------------------------------------------- */ +void Dblqh::execLQHKEYREQ(Signal* signal) +{ + UintR sig0, sig1, sig2, sig3, sig4, sig5; + Uint8 tfragDistKey; + + const LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)signal->getDataPtr(); + + sig0 = lqhKeyReq->clientConnectPtr; + if (cfirstfreeTcConrec != RNIL && !ERROR_INSERTED(5031)) { + jamEntry(); + seizeTcrec(); + } else { +/* ------------------------------------------------------------------------- */ +/* NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST. */ +/* ------------------------------------------------------------------------- */ + if (ERROR_INSERTED(5031)) { + CLEAR_ERROR_INSERT_VALUE; + } + noFreeRecordLab(signal, lqhKeyReq, ZNO_TC_CONNECT_ERROR); + return; + }//if + + if(ERROR_INSERTED(5038) && + refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ + jam(); + SET_ERROR_INSERT_VALUE(5039); + return; + } + + c_Counters.operations++; + + TcConnectionrec * const regTcPtr = tcConnectptr.p; + regTcPtr->clientBlockref = signal->senderBlockRef(); + regTcPtr->clientConnectrec = sig0; + regTcPtr->tcOprec = sig0; + regTcPtr->storedProcId = ZNIL; + + UintR TtotReclenAi = lqhKeyReq->attrLen; + sig1 = lqhKeyReq->savePointId; + sig2 = lqhKeyReq->hashValue; + UintR Treqinfo = lqhKeyReq->requestInfo; + sig4 = lqhKeyReq->tableSchemaVersion; + sig5 = lqhKeyReq->tcBlockref; + + regTcPtr->savePointId = sig1; + regTcPtr->hashValue = sig2; + const Uint32 schemaVersion = regTcPtr->schemaVersion = LqhKeyReq::getSchemaVersion(sig4); + tabptr.i = LqhKeyReq::getTableId(sig4); + regTcPtr->tcBlockref = sig5; + + const Uint8 op = LqhKeyReq::getOperation(Treqinfo); + if (op == ZREAD && !getAllowRead()){ + noFreeRecordLab(signal, lqhKeyReq, ZNODE_SHUTDOWN_IN_PROGESS); + return; + } + + regTcPtr->totReclenAi = LqhKeyReq::getAttrLen(TtotReclenAi); + regTcPtr->tcScanInfo = lqhKeyReq->scanInfo; + regTcPtr->indTakeOver = LqhKeyReq::getScanTakeOverFlag(TtotReclenAi); + + regTcPtr->readlenAi = 0; + regTcPtr->currTupAiLen = 0; + regTcPtr->listState = TcConnectionrec::NOT_IN_LIST; + regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; + regTcPtr->fragmentptr = RNIL; + + sig0 = lqhKeyReq->fragmentData; + sig1 = lqhKeyReq->transId1; + sig2 = lqhKeyReq->transId2; + sig3 = lqhKeyReq->variableData[0]; + sig4 = lqhKeyReq->variableData[1]; + + regTcPtr->fragmentid = LqhKeyReq::getFragmentId(sig0); + regTcPtr->nextReplica = LqhKeyReq::getNextReplicaNodeId(sig0); + regTcPtr->transid[0] = sig1; + regTcPtr->transid[1] = sig2; + regTcPtr->applRef = sig3; + regTcPtr->applOprec = sig4; + + regTcPtr->commitAckMarker = RNIL; + if(LqhKeyReq::getMarkerFlag(Treqinfo)){ + jam(); + + CommitAckMarkerPtr markerPtr; + m_commitAckMarkerHash.seize(markerPtr); + if(markerPtr.i == RNIL){ + noFreeRecordLab(signal, lqhKeyReq, ZNO_FREE_MARKER_RECORDS_ERROR); + return; + } + markerPtr.p->transid1 = sig1; + markerPtr.p->transid2 = sig2; + markerPtr.p->apiRef = sig3; + markerPtr.p->apiOprec = sig4; + const NodeId tcNodeId = refToNode(sig5); + markerPtr.p->tcNodeId = tcNodeId; + + CommitAckMarkerPtr tmp; +#ifdef VM_TRACE +#ifdef MARKER_TRACE + ndbout_c("Add marker[%.8x %.8x]", markerPtr.p->transid1, markerPtr.p->transid2); +#endif + ndbrequire(!m_commitAckMarkerHash.find(tmp, * markerPtr.p)); +#endif + m_commitAckMarkerHash.add(markerPtr); + regTcPtr->commitAckMarker = markerPtr.i; + } + + regTcPtr->reqinfo = Treqinfo; + regTcPtr->lastReplicaNo = LqhKeyReq::getLastReplicaNo(Treqinfo); + regTcPtr->lockType = LqhKeyReq::getLockType(Treqinfo); + regTcPtr->dirtyOp = LqhKeyReq::getDirtyFlag(Treqinfo); + regTcPtr->opExec = LqhKeyReq::getInterpretedFlag(Treqinfo); + regTcPtr->opSimple = LqhKeyReq::getSimpleFlag(Treqinfo); + regTcPtr->operation = LqhKeyReq::getOperation(Treqinfo); + regTcPtr->simpleRead = regTcPtr->operation == ZREAD && regTcPtr->opSimple; + regTcPtr->seqNoReplica = LqhKeyReq::getSeqNoReplica(Treqinfo); + UintR TreclenAiLqhkey = LqhKeyReq::getAIInLqhKeyReq(Treqinfo); + regTcPtr->apiVersionNo = 0; + + CRASH_INSERTION2(5041, regTcPtr->simpleRead && + refToNode(signal->senderBlockRef()) != cownNodeid); + + 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 & 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 == ZFALSE)) { + /* ---------------------------------------------------------------------- + * WE HAVE DIFFERENT OPINION THAN THE DIH THAT STARTED THE TRANSACTION. + * THE REASON COULD BE THAT THIS IS AN OLD DISTRIBUTION WHICH IS NO LONGER + * VALID TO USE. THIS MUST BE CHECKED. + * ONE IS ADDED TO THE DISTRIBUTION KEY EVERY TIME WE ADD A NEW REPLICA. + * FAILED REPLICAS DO NOT AFFECT THE DISTRIBUTION KEY. THIS MEANS THAT THE + * MAXIMUM DEVIATION CAN BE ONE BETWEEN THOSE TWO VALUES. + * --------------------------------------------------------------------- */ + Int32 tmp = TdistKey - tfragDistKey; + tmp = (tmp < 0 ? - tmp : tmp); + if ((tmp <= 1) || (tfragDistKey == 0)) { + LQHKEY_abort(signal, 0); + return; + }//if + LQHKEY_error(signal, 1); + }//if + if (TreclenAiLqhkey != 0) { + if (regTcPtr->operation != ZREAD) { + if (regTcPtr->operation != ZDELETE) { + if (regTcPtr->opExec != 1) { + jam(); +/*---------------------------------------------------------------------------*/ +/* */ +/* UPDATES, WRITES AND INSERTS THAT ARE NOT INTERPRETED WILL USE THE */ +/* SAME ATTRINFO IN ALL REPLICAS. THUS WE SAVE THE ATTRINFO ALREADY */ +/* TO SAVE A SIGNAL FROM TUP TO LQH. INTERPRETED EXECUTION IN TUP */ +/* WILL CREATE NEW ATTRINFO FOR THE OTHER REPLICAS AND IT IS THUS NOT */ +/* A GOOD IDEA TO SAVE THE INFORMATION HERE. READS WILL ALSO BE */ +/* UNNECESSARY TO SAVE SINCE THAT ATTRINFO WILL NEVER BE SENT TO ANY */ +/* MORE REPLICAS. */ +/*---------------------------------------------------------------------------*/ +/* READS AND DELETES CAN ONLY HAVE INFORMATION ABOUT WHAT IS TO BE READ. */ +/* NO INFORMATION THAT NEEDS LOGGING. */ +/*---------------------------------------------------------------------------*/ + sig0 = lqhKeyReq->variableData[nextPos + 0]; + sig1 = lqhKeyReq->variableData[nextPos + 1]; + sig2 = lqhKeyReq->variableData[nextPos + 2]; + sig3 = lqhKeyReq->variableData[nextPos + 3]; + sig4 = lqhKeyReq->variableData[nextPos + 4]; + + regTcPtr->firstAttrinfo[0] = sig0; + regTcPtr->firstAttrinfo[1] = sig1; + regTcPtr->firstAttrinfo[2] = sig2; + regTcPtr->firstAttrinfo[3] = sig3; + regTcPtr->firstAttrinfo[4] = sig4; + regTcPtr->currTupAiLen = TreclenAiLqhkey; + } else { + jam(); + regTcPtr->reclenAiLqhkey = 0; + }//if + } else { + jam(); + regTcPtr->reclenAiLqhkey = 0; + }//if + }//if + sig0 = lqhKeyReq->variableData[nextPos + 0]; + sig1 = lqhKeyReq->variableData[nextPos + 1]; + sig2 = lqhKeyReq->variableData[nextPos + 2]; + sig3 = lqhKeyReq->variableData[nextPos + 3]; + sig4 = lqhKeyReq->variableData[nextPos + 4]; + + signal->theData[0] = regTcPtr->tupConnectrec; + signal->theData[3] = sig0; + signal->theData[4] = sig1; + signal->theData[5] = sig2; + signal->theData[6] = sig3; + signal->theData[7] = sig4; + EXECUTE_DIRECT(refToBlock(regTcPtr->tcTupBlockref), GSN_ATTRINFO, + signal, TreclenAiLqhkey + 3); + jamEntry(); + if (signal->theData[0] == (UintR)-1) { + LQHKEY_abort(signal, 2); + return; + }//if + }//if +/* ------- TAKE CARE OF PRIM KEY DATA ------- */ + if (regTcPtr->primKeyLen <= 4) { + endgettupkeyLab(signal); + return; + } else { + jam(); +/*--------------------------------------------------------------------*/ +/* KEY LENGTH WAS MORE THAN 4 WORDS (WORD = 4 BYTE). THUS WE */ +/* HAVE TO ALLOCATE A DATA BUFFER TO STORE THE KEY DATA AND */ +/* WAIT FOR THE KEYINFO SIGNAL. */ +/*--------------------------------------------------------------------*/ + regTcPtr->save1 = 4; + regTcPtr->transactionState = TcConnectionrec::WAIT_TUPKEYINFO; + return; + }//if + return; +}//Dblqh::execLQHKEYREQ() + +void Dblqh::endgettupkeyLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->totReclenAi == regTcPtr->currReclenAi) { + ; + } else { + jam(); + ndbrequire(regTcPtr->currReclenAi < regTcPtr->totReclenAi); + regTcPtr->transactionState = TcConnectionrec::WAIT_ATTR; + return; + }//if +/* ---------------------------------------------------------------------- */ +/* NOW RECEPTION OF LQHKEYREQ IS COMPLETED THE NEXT STEP IS TO START*/ +/* PROCESSING THE MESSAGE. IF THE MESSAGE IS TO A STAND-BY NODE */ +/* WITHOUT NETWORK REDUNDANCY OR PREPARE-TO-COMMIT ACTIVATED THE */ +/* PREPARATION TO SEND TO THE NEXT NODE WILL START IMMEDIATELY. */ +/* */ +/* OTHERWISE THE PROCESSING WILL START AFTER SETTING THE PROPER */ +/* STATE. HOWEVER BEFORE PROCESSING THE MESSAGE */ +/* IT IS NECESSARY TO CHECK THAT THE FRAGMENT IS NOT PERFORMING */ +/* A CHECKPOINT. THE OPERATION SHALL ALSO BE LINKED INTO THE */ +/* FRAGMENT QUEUE OR LIST OF ACTIVE OPERATIONS. */ +/* */ +/* THE FIRST STEP IN PROCESSING THE MESSAGE IS TO CONTACT DBACC. */ +/*------------------------------------------------------------------------*/ + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + case Fragrecord::CRASH_RECOVERING: + case Fragrecord::ACTIVE_CREATION: + linkActiveFrag(signal); + prepareContinueAfterBlockedLab(signal); + return; + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + regTcPtr->transactionState = TcConnectionrec::STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + break; + }//switch + return; +}//Dblqh::endgettupkeyLab() + +void Dblqh::prepareContinueAfterBlockedLab(Signal* signal) +{ + UintR ttcScanOp; + UintR taccreq; + +/* -------------------------------------------------------------------------- */ +/* INPUT: TC_CONNECTPTR ACTIVE CONNECTION RECORD */ +/* FRAGPTR FRAGMENT RECORD */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT. */ +/* -------------------------------------------------------------------------- */ +/* ALSO AFTER NORMAL PROCEDURE WE CONTINUE HERE */ +/* -------------------------------------------------------------------------- */ + Uint32 tc_ptr_i = tcConnectptr.i; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->indTakeOver == ZTRUE) { + jam(); + ttcScanOp = KeyInfo20::getScanOp(regTcPtr->tcScanInfo); + scanptr.i = RNIL; + { + ScanRecord key; + key.scanNumber = KeyInfo20::getScanNo(regTcPtr->tcScanInfo); + key.fragPtrI = fragptr.i; + c_scanTakeOverHash.find(scanptr, key); +#ifdef TRACE_SCAN_TAKEOVER + if(scanptr.i == RNIL) + ndbout_c("not finding (%d %d)", key.scanNumber, key.fragPtrI); +#endif + } + if (scanptr.i == RNIL) { + jam(); + releaseActiveFrag(signal); + takeOverErrorLab(signal); + return; + }//if + Uint32 accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, + ttcScanOp, + true); + if (accOpPtr == RNIL) { + jam(); + releaseActiveFrag(signal); + takeOverErrorLab(signal); + return; + }//if + signal->theData[1] = accOpPtr; + signal->theData[2] = regTcPtr->transid[0]; + signal->theData[3] = regTcPtr->transid[1]; + EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACC_TO_REQ, + signal, 4); + if (signal->theData[0] == (UintR)-1) { + execACC_TO_REF(signal); + return; + }//if + jamEntry(); + }//if +/*-------------------------------------------------------------------*/ +/* IT IS NOW TIME TO CONTACT ACC. THE TUPLE KEY WILL BE SENT */ +/* AND THIS WILL BE TRANSLATED INTO A LOCAL KEY BY USING THE */ +/* LOCAL PART OF THE LH3-ALGORITHM. ALSO PROPER LOCKS ON THE */ +/* TUPLE WILL BE SET. FOR INSERTS AND DELETES THE MESSAGE WILL */ +/* START AN INSERT/DELETE INTO THE HASH TABLE. */ +/* */ +/* BEFORE SENDING THE MESSAGE THE REQUEST INFORMATION IS SET */ +/* PROPERLY. */ +/* ----------------------------------------------------------------- */ +#if 0 + if (regTcPtr->tableref != 0) { + switch (regTcPtr->operation) { + case ZREAD: ndbout << "Läsning "; break; + case ZUPDATE: ndbout << " Uppdatering "; break; + case ZWRITE: ndbout << "Write "; break; + case ZINSERT: ndbout << "Inläggning "; break; + case ZDELETE: ndbout << "Borttagning "; break; + default: ndbout << "????"; break; + } + ndbout << "med nyckel = " << regTcPtr->tupkeyData[0] << endl; + } +#endif + + regTcPtr->transactionState = TcConnectionrec::WAIT_ACC; + taccreq = regTcPtr->operation; + taccreq = taccreq + (regTcPtr->opSimple << 3); + taccreq = taccreq + (regTcPtr->lockType << 4); + taccreq = taccreq + (regTcPtr->dirtyOp << 6); + taccreq = taccreq + (regTcPtr->replicaType << 7); + taccreq = taccreq + (regTcPtr->apiVersionNo << 9); +/* ************ */ +/* ACCKEYREQ < */ +/* ************ */ + ndbrequire(regTcPtr->localFragptr < 2); + Uint32 sig0, sig1, sig2, sig3, sig4; + sig0 = regTcPtr->accConnectrec; + sig1 = fragptr.p->accFragptr[regTcPtr->localFragptr]; + sig2 = regTcPtr->hashValue; + sig3 = regTcPtr->primKeyLen; + sig4 = regTcPtr->transid[0]; + signal->theData[0] = sig0; + signal->theData[1] = sig1; + signal->theData[2] = taccreq; + signal->theData[3] = sig2; + signal->theData[4] = sig3; + signal->theData[5] = sig4; + + sig0 = regTcPtr->transid[1]; + sig1 = regTcPtr->tupkeyData[0]; + sig2 = regTcPtr->tupkeyData[1]; + sig3 = regTcPtr->tupkeyData[2]; + sig4 = regTcPtr->tupkeyData[3]; + signal->theData[6] = sig0; + signal->theData[7] = sig1; + signal->theData[8] = sig2; + signal->theData[9] = sig3; + signal->theData[10] = sig4; + if (regTcPtr->primKeyLen > 4) { + sendKeyinfoAcc(signal, 11); + }//if + EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACCKEYREQ, + signal, 7 + regTcPtr->primKeyLen); + if (signal->theData[0] < RNIL) { + signal->theData[0] = tc_ptr_i; + execACCKEYCONF(signal); + return; + } else if (signal->theData[0] == RNIL) { + ; + } else { + ndbrequire(signal->theData[0] == (UintR)-1); + signal->theData[0] = tc_ptr_i; + execACCKEYREF(signal); + }//if + return; +}//Dblqh::prepareContinueAfterBlockedLab() + +/* ========================================================================== */ +/* ======= SEND KEYINFO TO ACC ======= */ +/* */ +/* ========================================================================== */ +void Dblqh::sendKeyinfoAcc(Signal* signal, Uint32 Ti) +{ + DatabufPtr regDatabufptr; + regDatabufptr.i = tcConnectptr.p->firstTupkeybuf; + + do { + jam(); + ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); + Uint32 sig0 = regDatabufptr.p->data[0]; + Uint32 sig1 = regDatabufptr.p->data[1]; + Uint32 sig2 = regDatabufptr.p->data[2]; + Uint32 sig3 = regDatabufptr.p->data[3]; + signal->theData[Ti] = sig0; + signal->theData[Ti + 1] = sig1; + signal->theData[Ti + 2] = sig2; + signal->theData[Ti + 3] = sig3; + regDatabufptr.i = regDatabufptr.p->nextDatabuf; + Ti += 4; + } while (regDatabufptr.i != RNIL); +}//Dblqh::sendKeyinfoAcc() + +void Dblqh::execLQH_ALLOCREQ(Signal* signal) +{ + TcConnectionrecPtr regTcPtr; + FragrecordPtr regFragptr; + + jamEntry(); + regTcPtr.i = signal->theData[0]; + ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec); + + regFragptr.i = regTcPtr.p->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + + ndbrequire(regTcPtr.p->localFragptr < 2); + signal->theData[0] = regTcPtr.p->tupConnectrec; + signal->theData[1] = regFragptr.p->tupFragptr[regTcPtr.p->localFragptr]; + signal->theData[2] = regTcPtr.p->tableref; + Uint32 tup = refToBlock(regTcPtr.p->tcTupBlockref); + EXECUTE_DIRECT(tup, GSN_TUP_ALLOCREQ, signal, 3); +}//Dblqh::execTUP_ALLOCREQ() + +/* ************>> */ +/* ACCKEYCONF > */ +/* ************>> */ +void Dblqh::execACCKEYCONF(Signal* signal) +{ + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + Uint32 tcIndex = signal->theData[0]; + Uint32 Tfragid = signal->theData[2]; + Uint32 localKey1 = signal->theData[3]; + Uint32 localKey2 = signal->theData[4]; + Uint32 localKeyFlag = signal->theData[5]; + jamEntry(); + tcConnectptr.i = tcIndex; + ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec); + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->transactionState != TcConnectionrec::WAIT_ACC) { + LQHKEY_abort(signal, 3); + return; + }//if + /* ------------------------------------------------------------------------ + * Set transaction state and also reset the activeCreat since that is only + * valid in cases where the record was not present. + * ------------------------------------------------------------------------ */ + regTcPtr->transactionState = TcConnectionrec::WAIT_TUP; + regTcPtr->activeCreat = ZFALSE; + /* ------------------------------------------------------------------------ + * IT IS NOW TIME TO CONTACT THE TUPLE MANAGER. THE TUPLE MANAGER NEEDS THE + * INFORMATION ON WHICH TABLE AND FRAGMENT, THE LOCAL KEY AND IT NEEDS TO + * KNOW THE TYPE OF OPERATION TO PERFORM. TUP CAN SEND THE ATTRINFO DATA + * EITHER TO THE TC BLOCK OR DIRECTLY TO THE APPLICATION. THE SCHEMA VERSION + * IS NEEDED SINCE TWO SCHEMA VERSIONS CAN BE ACTIVE SIMULTANEOUSLY ON A + * TABLE. + * ------------------------------------------------------------------------ */ + if (regTcPtr->operation == ZWRITE) { + if (signal->theData[1] > 0) { + /* -------------------------------------------------------------------- + * ACC did perform an insert and thus we should indicate that the WRITE + * is an INSERT otherwise it is an UPDATE. + * -------------------------------------------------------------------- */ + jam(); + regTcPtr->operation = ZINSERT; + } else { + jam(); + tcConnectptr.p->operation = ZUPDATE; + }//if + }//if + ndbrequire(localKeyFlag == 1); + localKey2 = localKey1 & MAX_TUPLES_PER_PAGE; + localKey1 = localKey1 >> MAX_TUPLES_BITS; + Uint32 Ttupreq = regTcPtr->dirtyOp; + Ttupreq = Ttupreq + (regTcPtr->opSimple << 1); + Ttupreq = Ttupreq + (regTcPtr->operation << 6); + Ttupreq = Ttupreq + (regTcPtr->opExec << 10); + Ttupreq = Ttupreq + (regTcPtr->apiVersionNo << 11); + + /* --------------------------------------------------------------------- + * Clear interpreted mode bit since we do not want the next replica to + * use interpreted mode. The next replica will receive a normal write. + * --------------------------------------------------------------------- */ + regTcPtr->opExec = 0; + /* ************< */ + /* TUPKEYREQ < */ + /* ************< */ + TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); + Uint32 sig0, sig1, sig2, sig3; + + sig0 = regTcPtr->tupConnectrec; + sig1 = regTcPtr->tableref; + tupKeyReq->connectPtr = sig0; + tupKeyReq->request = Ttupreq; + tupKeyReq->tableRef = sig1; + tupKeyReq->fragId = Tfragid; + tupKeyReq->keyRef1 = localKey1; + tupKeyReq->keyRef2 = localKey2; + + sig0 = regTcPtr->totReclenAi; + sig1 = regTcPtr->applOprec; + sig2 = regTcPtr->applRef; + sig3 = regTcPtr->schemaVersion; + FragrecordPtr regFragptr; + regFragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + tupKeyReq->attrBufLen = sig0; + tupKeyReq->opRef = sig1; + tupKeyReq->applRef = sig2; + tupKeyReq->schemaVersion = sig3; + + ndbrequire(regTcPtr->localFragptr < 2); + sig0 = regTcPtr->storedProcId; + sig1 = regTcPtr->transid[0]; + sig2 = regTcPtr->transid[1]; + sig3 = regFragptr.p->tupFragptr[regTcPtr->localFragptr]; + Uint32 tup = refToBlock(regTcPtr->tcTupBlockref); + + tupKeyReq->storedProcedure = sig0; + tupKeyReq->transId1 = sig1; + tupKeyReq->transId2 = sig2; + tupKeyReq->fragPtr = sig3; + tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; + tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; + tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; + tupKeyReq->savePointId = tcConnectptr.p->savePointId; + + EXECUTE_DIRECT(tup, GSN_TUPKEYREQ, signal, TupKeyReq::SignalLength); +}//Dblqh::execACCKEYCONF() + +/* -------------------------------------------------------------------------- + * ------- ENTER TUP... ------- + * ENTER TUPKEYCONF WITH + * TC_CONNECTPTR, + * TDATA2, LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT + * TDATA3, LOCAL KEY REFERENCE 1, ONLY INTERESTING AFTER INSERT + * TDATA4, TOTAL LENGTH OF READ DATA SENT TO TC/APPLICATION + * TDATA5 TOTAL LENGTH OF UPDATE DATA SENT TO/FROM TUP + * GOTO TUPKEY_CONF + * + * TAKE CARE OF RESPONSES FROM TUPLE MANAGER. + * -------------------------------------------------------------------------- */ +void Dblqh::tupkeyConfLab(Signal* signal) +{ +/* ---- GET OPERATION TYPE AND CHECK WHAT KIND OF OPERATION IS REQUESTED ---- */ + const TupKeyConf * const tupKeyConf = (TupKeyConf *)&signal->theData[0]; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->simpleRead) { + jam(); + /* ---------------------------------------------------------------------- + * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE OPERATION. + * SINCE WE HAVE NOT RELEASED THE FRAGMENT LOCK (FOR LOCAL CHECKPOINTS) YET + * WE CAN GO IMMEDIATELY TO COMMIT_CONTINUE_AFTER_BLOCKED. + * WE HAVE ALREADY SENT THE RESPONSE SO WE ARE NOT INTERESTED IN READ LENGTH + * ---------------------------------------------------------------------- */ + regTcPtr->gci = cnewestGci; + releaseActiveFrag(signal); + commitContinueAfterBlockedLab(signal); + return; + }//if + if (tupKeyConf->readLength != 0) { + jam(); + + /* SET BIT 15 IN REQINFO */ + LqhKeyReq::setApplicationAddressFlag(regTcPtr->reqinfo, 1); + + regTcPtr->readlenAi = tupKeyConf->readLength; + }//if + regTcPtr->totSendlenAi = tupKeyConf->writeLength; + ndbrequire(regTcPtr->totSendlenAi == regTcPtr->currTupAiLen); + rwConcludedLab(signal); + return; +}//Dblqh::tupkeyConfLab() + +/* -------------------------------------------------------------------------- + * THE CODE IS FOUND IN THE SIGNAL RECEPTION PART OF LQH + * -------------------------------------------------------------------------- */ +void Dblqh::rwConcludedLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + /* ------------------------------------------------------------------------ + * WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION. + * IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND + * FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION. + * ------------------------------------------------------------------------ */ + if (regTcPtr->operation == ZREAD) { + jam(); + /* ---------------------------------------------------------------------- + * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL THE + * COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE. + * ---------------------------------------------------------------------- */ + releaseActiveFrag(signal); + packLqhkeyreqLab(signal); + return; + } else { + FragrecordPtr regFragptr; + regFragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + if (regFragptr.p->logFlag == Fragrecord::STATE_FALSE){ + if (regTcPtr->dirtyOp == ZTRUE) { + jam(); + /* ------------------------------------------------------------------ + * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND + * THAT CAN CAN BE COMMITTED IMMEDIATELY. + * ------------------------------------------------------------------ */ + regTcPtr->gci = cnewestGci; + releaseActiveFrag(signal); + commitContinueAfterBlockedLab(signal); + return; + } else { + jam(); + /* ------------------------------------------------------------------ + * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING. + * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC. + * ------------------------------------------------------------------ */ + regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN; + releaseActiveFrag(signal); + packLqhkeyreqLab(signal); + return; + }//if + } else { + jam(); + /* -------------------------------------------------------------------- + * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE + * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST. + * -------------------------------------------------------------------- + * A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE + * PREMATURELY COMMITTED. + * -------------------------------------------------------------------- */ + releaseActiveFrag(signal); + logLqhkeyreqLab(signal); + return; + }//if + }//if +}//Dblqh::rwConcludedLab() + +void Dblqh::rwConcludedAiLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + fragptr.i = regTcPtr->fragmentptr; + /* ------------------------------------------------------------------------ + * WE HAVE NOW CONCLUDED READING/WRITING IN ACC AND TUP FOR THIS OPERATION. + * IT IS NOW TIME TO LOG THE OPERATION, SEND REQUEST TO NEXT NODE OR TC AND + * FOR SOME TYPES OF OPERATIONS IT IS EVEN TIME TO COMMIT THE OPERATION. + * IN THIS CASE WE HAVE ALREADY RELEASED THE FRAGMENT LOCK. + * ERROR CASES AT FRAGMENT CREATION AND STAND-BY NODES ARE THE REASONS FOR + * COMING HERE. + * ------------------------------------------------------------------------ */ + if (regTcPtr->operation == ZREAD) { + if (regTcPtr->opSimple == 1) { + jam(); + /* -------------------------------------------------------------------- + * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE + * OPERATION. + * -------------------------------------------------------------------- */ + regTcPtr->gci = cnewestGci; + localCommitLab(signal); + return; + } else { + jam(); + /* -------------------------------------------------------------------- + * A NORMAL READ OPERATION IS NOT LOGGED BUT IS NOT COMMITTED UNTIL + * THE COMMIT SIGNAL ARRIVES. THUS WE CONTINUE PACKING THE RESPONSE. + * -------------------------------------------------------------------- */ + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + packLqhkeyreqLab(signal); + return; + }//if + } else { + jam(); + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (fragptr.p->logFlag == Fragrecord::STATE_FALSE) { + if (regTcPtr->dirtyOp == ZTRUE) { + /* ------------------------------------------------------------------ + * THIS OPERATION WAS A WRITE OPERATION THAT DO NOT NEED LOGGING AND + * THAT CAN CAN BE COMMITTED IMMEDIATELY. + * ------------------------------------------------------------------ */ + jam(); + /* ---------------------------------------------------------------- + * IT MUST BE ACTIVE CREATION OF A FRAGMENT. + * ---------------------------------------------------------------- */ + regTcPtr->gci = cnewestGci; + localCommitLab(signal); + return; + } else { + /* ------------------------------------------------------------------ + * A NORMAL WRITE OPERATION ON A FRAGMENT WHICH DO NOT NEED LOGGING. + * WE WILL PACK THE REQUEST/RESPONSE TO THE NEXT NODE/TO TC. + * ------------------------------------------------------------------ */ + jam(); + /* --------------------------------------------------------------- + * IT MUST BE ACTIVE CREATION OF A FRAGMENT. + * NOT A DIRTY OPERATION THUS PACK REQUEST/RESPONSE. + * ---------------------------------------------------------------- */ + regTcPtr->logWriteState = TcConnectionrec::NOT_WRITTEN; + packLqhkeyreqLab(signal); + return; + }//if + } else { + jam(); + /* -------------------------------------------------------------------- + * A DIRTY OPERATION WHICH NEEDS LOGGING. WE START BY LOGGING THE + * REQUEST. IN THIS CASE WE WILL RELEASE THE FRAGMENT LOCK FIRST. + * -------------------------------------------------------------------- */ + /* A NORMAL WRITE OPERATION THAT NEEDS LOGGING AND WILL NOT BE + * PREMATURELY COMMITTED. + * -------------------------------------------------------------------- */ + logLqhkeyreqLab(signal); + return; + }//if + }//if +}//Dblqh::rwConcludedAiLab() + +/* ########################################################################## + * ####### LOG MODULE ####### + * + * ########################################################################## + * -------------------------------------------------------------------------- + * THE LOG MODULE HANDLES THE READING AND WRITING OF THE LOG + * IT IS ALSO RESPONSIBLE FOR HANDLING THE SYSTEM RESTART. + * IT CONTROLS THE SYSTEM RESTART IN TUP AND ACC AS WELL. + * -------------------------------------------------------------------------- */ +void Dblqh::logLqhkeyreqLab(Signal* signal) +{ + UintR tcurrentFilepage; + TcConnectionrecPtr tmpTcConnectptr; + + if (cnoOfLogPages < ZMIN_LOG_PAGES_OPERATION || ERROR_INSERTED(5032)) { + jam(); + if(ERROR_INSERTED(5032)){ + CLEAR_ERROR_INSERT_VALUE; + } +/*---------------------------------------------------------------------------*/ +// The log disk is having problems in catching up with the speed of execution. +// We must wait with writing the log of this operation to ensure we do not +// overload the log. +/*---------------------------------------------------------------------------*/ + terrorCode = ZTEMPORARY_REDO_LOG_FAILURE; + abortErrorLab(signal); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + logPartPtr.i = regTcPtr->hashValue & 3; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); +/* -------------------------------------------------- */ +/* THIS PART IS USED TO WRITE THE LOG */ +/* -------------------------------------------------- */ +/* -------------------------------------------------- */ +/* CHECK IF A LOG OPERATION IS ONGOING ALREADY. */ +/* IF SO THEN QUEUE THE OPERATION FOR LATER */ +/* RESTART WHEN THE LOG PART IS FREE AGAIN. */ +/* -------------------------------------------------- */ + LogPartRecord * const regLogPartPtr = logPartPtr.p; + + if(ERROR_INSERTED(5033)){ + jam(); + CLEAR_ERROR_INSERT_VALUE; + + if ((regLogPartPtr->firstLogQueue != RNIL) && + (regLogPartPtr->LogLqhKeyReqSent == ZFALSE)) { + /* -------------------------------------------------- */ + /* WE HAVE A PROBLEM IN THAT THE LOG HAS NO */ + /* ROOM FOR ADDITIONAL OPERATIONS AT THE MOMENT.*/ + /* -------------------------------------------------- */ + /* -------------------------------------------------- */ + /* WE MUST STILL RESTART QUEUED OPERATIONS SO */ + /* THEY ALSO CAN BE ABORTED. */ + /* -------------------------------------------------- */ + regLogPartPtr->LogLqhKeyReqSent = ZTRUE; + signal->theData[0] = ZLOG_LQHKEYREQ; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//if + + terrorCode = ZTAIL_PROBLEM_IN_LOG_ERROR; + abortErrorLab(signal); + return; + } + + if (regLogPartPtr->logPartState == LogPartRecord::IDLE) { + ; + } else if (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) { + jam(); + linkWaitLog(signal, logPartPtr); + regTcPtr->transactionState = TcConnectionrec::LOG_QUEUED; + return; + } else { + if ((regLogPartPtr->firstLogQueue != RNIL) && + (regLogPartPtr->LogLqhKeyReqSent == ZFALSE)) { +/* -------------------------------------------------- */ +/* WE HAVE A PROBLEM IN THAT THE LOG HAS NO */ +/* ROOM FOR ADDITIONAL OPERATIONS AT THE MOMENT.*/ +/* -------------------------------------------------- */ +/* -------------------------------------------------- */ +/* WE MUST STILL RESTART QUEUED OPERATIONS SO */ +/* THEY ALSO CAN BE ABORTED. */ +/* -------------------------------------------------- */ + regLogPartPtr->LogLqhKeyReqSent = ZTRUE; + signal->theData[0] = ZLOG_LQHKEYREQ; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//if + if (regLogPartPtr->logPartState == LogPartRecord::TAIL_PROBLEM) { + jam(); + terrorCode = ZTAIL_PROBLEM_IN_LOG_ERROR; + } else { + ndbrequire(regLogPartPtr->logPartState == LogPartRecord::FILE_CHANGE_PROBLEM); + jam(); + terrorCode = ZFILE_CHANGE_PROBLEM_IN_LOG_ERROR; + }//if + abortErrorLab(signal); + return; + }//if + regLogPartPtr->logPartState = LogPartRecord::ACTIVE; + logFilePtr.i = regLogPartPtr->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); +/* -------------------------------------------------- */ +/* CHECK IF A NEW MBYTE IS TO BE STARTED. IF */ +/* SO INSERT A NEXT LOG RECORD, WRITE THE LOG */ +/* AND PLACE THE LOG POINTER ON THE NEW POSITION*/ +/* IF A NEW FILE IS TO BE USED, CHANGE FILE AND */ +/* ALSO START OPENING THE NEXT LOG FILE. IF A */ +/* LAP HAS BEEN COMPLETED THEN ADD ONE TO LAP */ +/* COUNTER. */ +/* -------------------------------------------------- */ + checkNewMbyte(signal); +/* -------------------------------------------------- */ +/* INSERT THE OPERATION RECORD LAST IN THE LIST */ +/* OF NOT COMPLETED OPERATIONS. ALSO RECORD THE */ +/* FILE NO, PAGE NO AND PAGE INDEX OF THE START */ +/* OF THIS LOG RECORD. */ +/* IT IS NOT ALLOWED TO INSERT IT INTO THE LIST */ +/* BEFORE CHECKING THE NEW MBYTE SINCE THAT WILL*/ +/* CAUSE THE OLD VALUES OF TC_CONNECTPTR TO BE */ +/* USED IN WRITE_FILE_DESCRIPTOR. */ +/* -------------------------------------------------- */ + Uint32 tcIndex = tcConnectptr.i; + tmpTcConnectptr.i = regLogPartPtr->lastLogTcrec; + regLogPartPtr->lastLogTcrec = tcIndex; + if (tmpTcConnectptr.i == RNIL) { + jam(); + regLogPartPtr->firstLogTcrec = tcIndex; + } else { + ptrCheckGuard(tmpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + tmpTcConnectptr.p->nextLogTcrec = tcIndex; + }//if + Uint32 fileNo = logFilePtr.p->fileNo; + tcurrentFilepage = logFilePtr.p->currentFilepage; + logPagePtr.i = logFilePtr.p->currentLogpage; + regTcPtr->nextLogTcrec = RNIL; + regTcPtr->prevLogTcrec = tmpTcConnectptr.i; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + Uint32 pageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + regTcPtr->logStartFileNo = fileNo; + regTcPtr->logStartPageNo = tcurrentFilepage; + regTcPtr->logStartPageIndex = pageIndex; +/* -------------------------------------------------- */ +/* WRITE THE LOG HEADER OF THIS OPERATION. */ +/* -------------------------------------------------- */ + writeLogHeader(signal); +/* -------------------------------------------------- */ +/* WRITE THE TUPLE KEY OF THIS OPERATION. */ +/* -------------------------------------------------- */ + writeKey(signal); +/* -------------------------------------------------- */ +/* WRITE THE ATTRIBUTE INFO OF THIS OPERATION. */ +/* -------------------------------------------------- */ + writeAttrinfoLab(signal); + + logNextStart(signal); +/* -------------------------------------------------- */ +/* RESET THE STATE OF THE LOG PART. IF ANY */ +/* OPERATIONS HAVE QUEUED THEN START THE FIRST */ +/* OF THESE. */ +/* -------------------------------------------------- */ +/* -------------------------------------------------- */ +/* CONTINUE WITH PACKING OF LQHKEYREQ */ +/* -------------------------------------------------- */ + tcurrentFilepage = logFilePtr.p->currentFilepage; + if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) { + jam(); + tcurrentFilepage--; + }//if + regTcPtr->logStopPageNo = tcurrentFilepage; + regTcPtr->logWriteState = TcConnectionrec::WRITTEN; + if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { +/* -------------------------------------------------- */ +/* AN ABORT HAVE BEEN ORDERED. THE ABORT WAITED */ +/* FOR THE LOG WRITE TO BE COMPLETED. NOW WE */ +/* CAN PROCEED WITH THE NORMAL ABORT HANDLING. */ +/* -------------------------------------------------- */ + abortCommonLab(signal); + return; + }//if + if (regTcPtr->dirtyOp != ZTRUE) { + packLqhkeyreqLab(signal); + } else { + /* ---------------------------------------------------------------------- + * I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS + * TRANSACTION. SINCE WE RELEASED THE LOG LOCK JUST NOW NO ONE ELSE CAN BE + * ACTIVE IN WRITING THE LOG. WE THUS WRITE THE LOG WITHOUT GETTING A LOCK + * SINCE WE ARE ONLY WRITING A COMMIT LOG RECORD. + * ---------------------------------------------------------------------- */ + writeCommitLog(signal, logPartPtr); + /* ---------------------------------------------------------------------- + * DIRTY OPERATIONS SHOULD COMMIT BEFORE THEY PACK THE REQUEST/RESPONSE. + * ---------------------------------------------------------------------- */ + regTcPtr->gci = cnewestGci; + localCommitLab(signal); + }//if +}//Dblqh::logLqhkeyreqLab() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND LQHKEYREQ */ +/* */ +/* NO STATE CHECKING SINCE THE SIGNAL IS A LOCAL SIGNAL. THE EXECUTION OF */ +/* THE OPERATION IS COMPLETED. IT IS NOW TIME TO SEND THE OPERATION TO THE */ +/* NEXT REPLICA OR TO TC. */ +/* ------------------------------------------------------------------------- */ +void Dblqh::packLqhkeyreqLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->nextReplica == ZNIL) { +/* ------------------------------------------------------------------------- */ +/* ------- SEND LQHKEYCONF ------- */ +/* */ +/* ------------------------------------------------------------------------- */ + sendLqhkeyconfTc(signal, regTcPtr->tcBlockref); + if (regTcPtr->dirtyOp != ZTRUE) { + jam(); + regTcPtr->transactionState = TcConnectionrec::PREPARED; + releaseOprec(signal); + } else { + jam(); +/*************************************************************>*/ +/* DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST */ +/* SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/ +/* OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */ +/* NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE */ +/* SENT AS PART OF A COPY FRAGMENT PROCESS. */ +/* */ +/* DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING */ +/* ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE */ +/* LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE */ +/* OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES */ +/* ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT */ +/* REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */ +/* THOSE OPERATIONS ARE NOT INTERESTING. */ +/* */ +/* A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS */ +/* IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */ +/* ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */ +/* THIS NODE. */ +/*************************************************************>*/ + cleanUp(signal); + }//if + return; + }//if +/* ------------------------------------------------------------------------- */ +/* ------- SEND LQHKEYREQ ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* THERE ARE MORE REPLICAS TO SEND THE OPERATION TO. A NEW LQHKEYREQ WILL BE */ +/* PREPARED FOR THE NEXT REPLICA. */ +/* ------------------------------------------------------------------------- */ +/* CLEAR REPLICA TYPE, ATTRINFO INDICATOR (IN LQHKEYREQ), */ +/* INTERPRETED EXECUTION, SEQUENTIAL NUMBER OF REPLICA. */ +// Set bit indicating Client and TC record not the same. +// Set readlenAi indicator if readlenAi != 0 +// Stored Procedure Indicator not set. +/* ------------------------------------------------------------------------- */ + LqhKeyReq * const lqhKeyReq = (LqhKeyReq *)&signal->theData[0]; + + UintR Treqinfo; + UintR sig0, sig1, sig2, sig3, sig4, sig5, sig6; + Treqinfo = preComputedRequestInfoMask & regTcPtr->reqinfo; + + UintR TapplAddressIndicator = (regTcPtr->nextSeqNoReplica == 0 ? 0 : 1); + LqhKeyReq::setApplicationAddressFlag(Treqinfo, TapplAddressIndicator); + LqhKeyReq::setInterpretedFlag(Treqinfo, regTcPtr->opExec); + LqhKeyReq::setSeqNoReplica(Treqinfo, regTcPtr->nextSeqNoReplica); + LqhKeyReq::setAIInLqhKeyReq(Treqinfo, regTcPtr->reclenAiLqhkey); + UintR TreadLenAiInd = (regTcPtr->readlenAi == 0 ? 0 : 1); + UintR TsameLqhAndClient = (tcConnectptr.i == + regTcPtr->tcOprec ? 0 : 1); + LqhKeyReq::setSameClientAndTcFlag(Treqinfo, TsameLqhAndClient); + LqhKeyReq::setReturnedReadLenAIFlag(Treqinfo, TreadLenAiInd); + + UintR TotReclenAi = regTcPtr->totSendlenAi; +/* ------------------------------------------------------------------------- */ +/* WE ARE NOW PREPARED TO SEND THE LQHKEYREQ. WE HAVE TO DECIDE IF ATTRINFO */ +/* IS INCLUDED IN THE LQHKEYREQ SIGNAL AND THEN SEND IT. */ +/* TAKE OVER SCAN OPERATION IS NEVER USED ON BACKUPS, LOG RECORDS AND START-UP*/ +/* OF NEW REPLICA AND THUS ONLY TOT_SENDLEN_AI IS USED THE UPPER 16 BITS ARE */ +/* ZERO. */ +/* ------------------------------------------------------------------------- */ + sig0 = tcConnectptr.i; + sig1 = regTcPtr->savePointId; + sig2 = regTcPtr->hashValue; + sig4 = regTcPtr->tcBlockref; + + lqhKeyReq->clientConnectPtr = sig0; + lqhKeyReq->attrLen = TotReclenAi; + lqhKeyReq->savePointId = sig1; + lqhKeyReq->hashValue = sig2; + lqhKeyReq->requestInfo = Treqinfo; + lqhKeyReq->tcBlockref = sig4; + + sig0 = regTcPtr->tableref + (regTcPtr->schemaVersion << 16); + sig1 = regTcPtr->fragmentid + (regTcPtr->nodeAfterNext[0] << 16); + sig2 = regTcPtr->transid[0]; + sig3 = regTcPtr->transid[1]; + sig4 = regTcPtr->applRef; + sig5 = regTcPtr->applOprec; + sig6 = regTcPtr->tcOprec; + UintR nextPos = (TapplAddressIndicator << 1); + + lqhKeyReq->tableSchemaVersion = sig0; + lqhKeyReq->fragmentData = sig1; + lqhKeyReq->transId1 = sig2; + lqhKeyReq->transId2 = sig3; + lqhKeyReq->noFiredTriggers = regTcPtr->noFiredTriggers; + lqhKeyReq->variableData[0] = sig4; + lqhKeyReq->variableData[1] = sig5; + lqhKeyReq->variableData[2] = sig6; + + nextPos += TsameLqhAndClient; + + if ((regTcPtr->lastReplicaNo - regTcPtr->nextSeqNoReplica) > 1) { + sig0 = (UintR)regTcPtr->nodeAfterNext[1] + + (UintR)(regTcPtr->nodeAfterNext[2] << 16); + lqhKeyReq->variableData[nextPos] = sig0; + nextPos++; + }//if + sig0 = regTcPtr->readlenAi; + sig1 = regTcPtr->tupkeyData[0]; + sig2 = regTcPtr->tupkeyData[1]; + sig3 = regTcPtr->tupkeyData[2]; + sig4 = regTcPtr->tupkeyData[3]; + + lqhKeyReq->variableData[nextPos] = sig0; + nextPos += TreadLenAiInd; + lqhKeyReq->variableData[nextPos] = sig1; + lqhKeyReq->variableData[nextPos + 1] = sig2; + lqhKeyReq->variableData[nextPos + 2] = sig3; + lqhKeyReq->variableData[nextPos + 3] = sig4; + UintR TkeyLen = LqhKeyReq::getKeyLen(Treqinfo); + if (TkeyLen < 4) { + nextPos += TkeyLen; + } else { + nextPos += 4; + }//if + + sig0 = regTcPtr->firstAttrinfo[0]; + sig1 = regTcPtr->firstAttrinfo[1]; + sig2 = regTcPtr->firstAttrinfo[2]; + sig3 = regTcPtr->firstAttrinfo[3]; + sig4 = regTcPtr->firstAttrinfo[4]; + UintR TAiLen = regTcPtr->reclenAiLqhkey; + BlockReference lqhRef = calcLqhBlockRef(regTcPtr->nextReplica); + + lqhKeyReq->variableData[nextPos] = sig0; + lqhKeyReq->variableData[nextPos + 1] = sig1; + lqhKeyReq->variableData[nextPos + 2] = sig2; + lqhKeyReq->variableData[nextPos + 3] = sig3; + lqhKeyReq->variableData[nextPos + 4] = sig4; + + nextPos += TAiLen; + + sendSignal(lqhRef, GSN_LQHKEYREQ, signal, + nextPos + LqhKeyReq::FixedSignalLength, JBB); + if (regTcPtr->primKeyLen > 4) { + jam(); +/* ------------------------------------------------------------------------- */ +/* MORE THAN 4 WORDS OF KEY DATA IS IN THE OPERATION. THEREFORE WE NEED TO */ +/* PREPARE A KEYINFO SIGNAL. MORE THAN ONE KEYINFO SIGNAL CAN BE SENT. */ +/* ------------------------------------------------------------------------- */ + sendTupkey(signal); + }//if +/* ------------------------------------------------------------------------- */ +/* NOW I AM PREPARED TO SEND ALL THE ATTRINFO SIGNALS. AT THE MOMENT A LOOP */ +/* SENDS ALL AT ONCE. LATER WE HAVE TO ADDRESS THE PROBLEM THAT THESE COULD */ +/* LEAD TO BUFFER EXPLOSION => NODE CRASH. */ +/* ------------------------------------------------------------------------- */ +/* NEW CODE TO SEND ATTRINFO IN PACK_LQHKEYREQ */ +/* THIS CODE USES A REAL-TIME BREAK AFTER */ +/* SENDING 16 SIGNALS. */ +/* -------------------------------------------------- */ + sig0 = regTcPtr->tcOprec; + sig1 = regTcPtr->transid[0]; + sig2 = regTcPtr->transid[1]; + signal->theData[0] = sig0; + signal->theData[1] = sig1; + signal->theData[2] = sig2; + AttrbufPtr regAttrinbufptr; + regAttrinbufptr.i = regTcPtr->firstAttrinbuf; + while (regAttrinbufptr.i != RNIL) { + ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); + jam(); + Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; + ndbrequire(dataLen != 0); + MEMCOPY_NO_WORDS(&signal->theData[3], ®Attrinbufptr.p->attrbuf[0], dataLen); + regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; + sendSignal(lqhRef, GSN_ATTRINFO, signal, dataLen + 3, JBB); + }//while + regTcPtr->transactionState = TcConnectionrec::PREPARED; + if (regTcPtr->dirtyOp == ZTRUE) { + jam(); +/*************************************************************>*/ +/* DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST */ +/* SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/ +/* OTHER ATTRIBUTES WHICH ARE NOT SENSITIVE TO CONSISTE- */ +/* NCY. THE SECOND SITUATION IS BY OPERATIONS THAT ARE */ +/* SENT AS PART OF A COPY FRAGMENT PROCESS. */ +/* */ +/* DURING A COPY FRAGMENT PROCESS THERE IS NO LOGGING */ +/* ONGOING SINCE THE FRAGMENT IS NOT COMPLETE YET. THE */ +/* LOGGING STARTS AFTER COMPLETING THE LAST COPY TUPLE */ +/* OPERATION. THE EXECUTION OF THE LAST COPY TUPLE DOES */ +/* ALSO START A LOCAL CHECKPOINT SO THAT THE FRAGMENT */ +/* REPLICA IS RECOVERABLE. THUS GLOBAL CHECKPOINT ID FOR */ +/* THOSE OPERATIONS ARE NOT INTERESTING. */ +/* */ +/* A DIRTY WRITE IS BY DEFINITION NOT CONSISTENT. THUS */ +/* IT CAN USE ANY GLOBAL CHECKPOINT. THE IDEA HERE IS TO */ +/* ALWAYS USE THE LATEST DEFINED GLOBAL CHECKPOINT ID IN */ +/* THIS NODE. */ +/*************************************************************>*/ + cleanUp(signal); + return; + }//if + /* ------------------------------------------------------------------------ + * ALL INFORMATION NEEDED BY THE COMMIT PHASE AND COMPLETE PHASE IS + * KEPT IN THE TC_CONNECT RECORD. TO ENSURE PROPER USE OF MEMORY + * RESOURCES WE DEALLOCATE THE ATTRINFO RECORD AND KEY RECORDS + * AS SOON AS POSSIBLE. + * ------------------------------------------------------------------------ */ + releaseOprec(signal); +}//Dblqh::packLqhkeyreqLab() + +/* ========================================================================= */ +/* ==== CHECK IF THE LOG RECORD FITS INTO THE CURRENT MBYTE, ======= */ +/* OTHERWISE SWITCH TO NEXT MBYTE. */ +/* */ +/* ========================================================================= */ +void Dblqh::checkNewMbyte(Signal* signal) +{ + UintR tcnmTmp; + UintR ttotalLogSize; + +/* -------------------------------------------------- */ +/* CHECK IF A NEW MBYTE OF LOG RECORD IS TO BE */ +/* OPENED BEFORE WRITING THE LOG RECORD. NO LOG */ +/* RECORDS ARE ALLOWED TO SPAN A MBYTE BOUNDARY */ +/* */ +/* INPUT: TC_CONNECTPTR THE OPERATION */ +/* LOG_FILE_PTR THE LOG FILE */ +/* OUTPUT: LOG_FILE_PTR THE NEW LOG FILE */ +/* -------------------------------------------------- */ + ttotalLogSize = ZLOG_HEAD_SIZE + tcConnectptr.p->currTupAiLen; + ttotalLogSize = ttotalLogSize + tcConnectptr.p->primKeyLen; + tcnmTmp = logFilePtr.p->remainingWordsInMbyte; + if ((ttotalLogSize + ZNEXT_LOG_SIZE) <= tcnmTmp) { + ndbrequire(tcnmTmp >= ttotalLogSize); + logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize; + return; + } else { + jam(); +/* -------------------------------------------------- */ +/* IT WAS NOT ENOUGH SPACE IN THIS MBYTE FOR */ +/* THIS LOG RECORD. MOVE TO NEXT MBYTE */ +/* THIS MIGHT INCLUDE CHANGING LOG FILE */ +/* -------------------------------------------------- */ +/* WE HAVE TO INSERT A NEXT LOG RECORD FIRST */ +/* -------------------------------------------------- */ +/* THEN CONTINUE BY WRITING THE FILE DESCRIPTORS*/ +/* -------------------------------------------------- */ + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + changeMbyte(signal); + tcnmTmp = logFilePtr.p->remainingWordsInMbyte; + }//if + ndbrequire(tcnmTmp >= ttotalLogSize); + logFilePtr.p->remainingWordsInMbyte = tcnmTmp - ttotalLogSize; +}//Dblqh::checkNewMbyte() + +/* -------------------------------------------------------------------------- + * ------- WRITE OPERATION HEADER TO LOG ------- + * + * SUBROUTINE SHORT NAME: WLH + * ------------------------------------------------------------------------- */ +void Dblqh::writeLogHeader(Signal* signal) +{ + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + Uint32 hashValue = tcConnectptr.p->hashValue; + Uint32 operation = tcConnectptr.p->operation; + Uint32 keyLen = tcConnectptr.p->primKeyLen; + Uint32 aiLen = tcConnectptr.p->currTupAiLen; + Uint32 totLogLen = aiLen + keyLen + ZLOG_HEAD_SIZE; + if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) { + Uint32* dataPtr = &logPagePtr.p->logPageWord[logPos]; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE; + dataPtr[0] = ZPREP_OP_TYPE; + dataPtr[1] = totLogLen; + dataPtr[2] = hashValue; + dataPtr[3] = operation; + dataPtr[4] = aiLen; + dataPtr[5] = keyLen; + } else { + writeLogWord(signal, ZPREP_OP_TYPE); + writeLogWord(signal, totLogLen); + writeLogWord(signal, hashValue); + writeLogWord(signal, operation); + writeLogWord(signal, aiLen); + writeLogWord(signal, keyLen); + }//if +}//Dblqh::writeLogHeader() + +/* -------------------------------------------------------------------------- + * ------- WRITE TUPLE KEY TO LOG ------- + * + * SUBROUTINE SHORT NAME: WK + * ------------------------------------------------------------------------- */ +void Dblqh::writeKey(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 logPos, endPos, dataLen; + Int32 remainingLen; + logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + remainingLen = regTcPtr->primKeyLen; + dataLen = remainingLen; + if (remainingLen > 4) + dataLen = 4; + remainingLen -= dataLen; + endPos = logPos + dataLen; + if (endPos < ZPAGE_SIZE) { + MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], + ®TcPtr->tupkeyData[0], + dataLen); + } else { + jam(); + for (Uint32 i = 0; i < dataLen; i++) + writeLogWord(signal, regTcPtr->tupkeyData[i]); + endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + }//if + DatabufPtr regDatabufptr; + regDatabufptr.i = regTcPtr->firstTupkeybuf; + while (remainingLen > 0) { + logPos = endPos; + ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); + dataLen = remainingLen; + if (remainingLen > 4) + dataLen = 4; + remainingLen -= dataLen; + endPos += dataLen; + if (endPos < ZPAGE_SIZE) { + MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], + ®Databufptr.p->data[0], + dataLen); + } else { + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; + for (Uint32 i = 0; i < dataLen; i++) + writeLogWord(signal, regDatabufptr.p->data[i]); + endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + }//if + regDatabufptr.i = regDatabufptr.p->nextDatabuf; + }//while + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = endPos; + ndbrequire(regDatabufptr.i == RNIL); +}//Dblqh::writeKey() + +/* -------------------------------------------------------------------------- + * ------- WRITE ATTRINFO TO LOG ------- + * + * SUBROUTINE SHORT NAME: WA + * ------------------------------------------------------------------------- */ +void Dblqh::writeAttrinfoLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 totLen = regTcPtr->currTupAiLen; + if (totLen == 0) + return; + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + Uint32 lqhLen = regTcPtr->reclenAiLqhkey; + ndbrequire(totLen >= lqhLen); + Uint32 endPos = logPos + lqhLen; + totLen -= lqhLen; + if (endPos < ZPAGE_SIZE) { + MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], + ®TcPtr->firstAttrinfo[0], + lqhLen); + } else { + for (Uint32 i = 0; i < lqhLen; i++) + writeLogWord(signal, regTcPtr->firstAttrinfo[i]); + endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + }//if + AttrbufPtr regAttrinbufptr; + regAttrinbufptr.i = regTcPtr->firstAttrinbuf; + while (totLen > 0) { + logPos = endPos; + ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); + Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; + ndbrequire(totLen >= dataLen); + ndbrequire(dataLen > 0); + totLen -= dataLen; + endPos += dataLen; + if (endPos < ZPAGE_SIZE) { + MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[logPos], + ®Attrinbufptr.p->attrbuf[0], + dataLen); + } else { + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; + for (Uint32 i = 0; i < dataLen; i++) + writeLogWord(signal, regAttrinbufptr.p->attrbuf[i]); + endPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + }//if + regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; + }//while + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = endPos; + ndbrequire(regAttrinbufptr.i == RNIL); +}//Dblqh::writeAttrinfoLab() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND TUPLE KEY IN KEYINFO SIGNAL(S) ------- */ +/* */ +/* SUBROUTINE SHORT NAME: STU */ +/* ------------------------------------------------------------------------- */ +void Dblqh::sendTupkey(Signal* signal) +{ + UintR TdataPos = 3; + BlockReference lqhRef = calcLqhBlockRef(tcConnectptr.p->nextReplica); + signal->theData[0] = tcConnectptr.p->tcOprec; + signal->theData[1] = tcConnectptr.p->transid[0]; + signal->theData[2] = tcConnectptr.p->transid[1]; + databufptr.i = tcConnectptr.p->firstTupkeybuf; + do { + ptrCheckGuard(databufptr, cdatabufFileSize, databuf); + signal->theData[TdataPos] = databufptr.p->data[0]; + signal->theData[TdataPos + 1] = databufptr.p->data[1]; + signal->theData[TdataPos + 2] = databufptr.p->data[2]; + signal->theData[TdataPos + 3] = databufptr.p->data[3]; + + databufptr.i = databufptr.p->nextDatabuf; + TdataPos += 4; + if (databufptr.i == RNIL) { + jam(); + sendSignal(lqhRef, GSN_KEYINFO, signal, TdataPos, JBB); + return; + } else if (TdataPos == 23) { + jam(); + sendSignal(lqhRef, GSN_KEYINFO, signal, 23, JBB); + TdataPos = 3; + } + } while (1); +}//Dblqh::sendTupkey() + +void Dblqh::cleanUp(Signal* signal) +{ + releaseOprec(signal); + deleteTransidHash(signal); + releaseTcrec(signal, tcConnectptr); +}//Dblqh::cleanUp() + +/* -------------------------------------------------------------------------- + * ---- RELEASE ALL RECORDS CONNECTED TO THE OPERATION RECORD AND THE ---- + * OPERATION RECORD ITSELF + * ------------------------------------------------------------------------- */ +void Dblqh::releaseOprec(Signal* signal) +{ + UintR Tmpbuf; + TcConnectionrec * const regTcPtr = tcConnectptr.p; +/* ---- RELEASE DATA BUFFERS ------------------- */ + DatabufPtr regDatabufptr; + regDatabufptr.i = regTcPtr->firstTupkeybuf; +/* -------------------------------------------------------------------------- + * ------- RELEASE DATA BUFFERS ------- + * + * ------------------------------------------------------------------------- */ + + while (regDatabufptr.i != RNIL) { + jam(); + ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); + Tmpbuf = regDatabufptr.p->nextDatabuf; + regDatabufptr.p->nextDatabuf = cfirstfreeDatabuf; + cfirstfreeDatabuf = regDatabufptr.i; + regDatabufptr.i = Tmpbuf; + }//while +/* ---- RELEASE ATTRINFO BUFFERS ------------------- */ + AttrbufPtr regAttrinbufptr; + regAttrinbufptr.i = regTcPtr->firstAttrinbuf; + /* ######################################################################## + * ####### RELEASE_ATTRINBUF ####### + * + * ####################################################################### */ + while (regAttrinbufptr.i != RNIL) { + jam(); + regAttrinbufptr.i= release_attrinbuf(regAttrinbufptr.i); + }//while + regTcPtr->firstAttrinbuf = RNIL; + regTcPtr->lastAttrinbuf = RNIL; + regTcPtr->firstTupkeybuf = RNIL; + regTcPtr->lastTupkeybuf = RNIL; +}//Dblqh::releaseOprec() + +/* ------------------------------------------------------------------------- */ +/* ------ DELETE TRANSACTION ID FROM HASH TABLE ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::deleteTransidHash(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + TcConnectionrecPtr prevHashptr; + TcConnectionrecPtr nextHashptr; + + prevHashptr.i = regTcPtr->prevHashRec; + nextHashptr.i = regTcPtr->nextHashRec; + if (prevHashptr.i != RNIL) { + jam(); + ptrCheckGuard(prevHashptr, ctcConnectrecFileSize, tcConnectionrec); + prevHashptr.p->nextHashRec = nextHashptr.i; + } else { + jam(); +/* ------------------------------------------------------------------------- */ +/* THE OPERATION WAS PLACED FIRST IN THE LIST OF THE HASH TABLE. NEED TO SET */ +/* A NEW LEADER OF THE LIST. */ +/* ------------------------------------------------------------------------- */ + Uint32 hashIndex = (regTcPtr->transid[0] ^ regTcPtr->tcOprec) & 1023; + ctransidHash[hashIndex] = nextHashptr.i; + }//if + if (nextHashptr.i != RNIL) { + jam(); + ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec); + nextHashptr.p->prevHashRec = prevHashptr.i; + }//if +}//Dblqh::deleteTransidHash() + +/* -------------------------------------------------------------------------- + * ------- LINK OPERATION IN ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME: LAF +// Input Pointers: +// tcConnectptr +// fragptr + * ------------------------------------------------------------------------- */ +void Dblqh::linkActiveFrag(Signal* signal) +{ + TcConnectionrecPtr lafTcConnectptr; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Fragrecord * const regFragPtr = fragptr.p; + Uint32 tcIndex = tcConnectptr.i; + lafTcConnectptr.i = regFragPtr->activeList; + regTcPtr->prevTc = RNIL; + regFragPtr->activeList = tcIndex; + ndbrequire(regTcPtr->listState == TcConnectionrec::NOT_IN_LIST); + regTcPtr->nextTc = lafTcConnectptr.i; + regTcPtr->listState = TcConnectionrec::IN_ACTIVE_LIST; + if (lafTcConnectptr.i == RNIL) { + return; + } else { + jam(); + ptrCheckGuard(lafTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + lafTcConnectptr.p->prevTc = tcIndex; + }//if + return; +}//Dblqh::linkActiveFrag() + +/* ------------------------------------------------------------------------- + * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME = RAF + * ------------------------------------------------------------------------- */ +void Dblqh::releaseActiveFrag(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + TcConnectionrecPtr ralTcNextConnectptr; + TcConnectionrecPtr ralTcPrevConnectptr; + fragptr.i = regTcPtr->fragmentptr; + ralTcPrevConnectptr.i = regTcPtr->prevTc; + ralTcNextConnectptr.i = regTcPtr->nextTc; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + Fragrecord * const regFragPtr = fragptr.p; + ndbrequire(regTcPtr->listState == TcConnectionrec::IN_ACTIVE_LIST); + regTcPtr->listState = TcConnectionrec::NOT_IN_LIST; + + if (ralTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(ralTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + ralTcNextConnectptr.p->prevTc = ralTcPrevConnectptr.i; + }//if + if (ralTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(ralTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + ralTcPrevConnectptr.p->nextTc = regTcPtr->nextTc; + } else { + jam(); + /* ---------------------------------------------------------------------- + * OPERATION RECORD IS FIRST IN ACTIVE LIST + * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. + * --------------------------------------------------------------------- */ + regFragPtr->activeList = ralTcNextConnectptr.i; + }//if + if (regFragPtr->lcpRef != RNIL) { + jam(); + lcpPtr.i = regFragPtr->lcpRef; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_ACTIVE_FINISH); + + /* -------------------------------------------------------------------- + * IF A FRAGMENT IS CURRENTLY STARTING A LOCAL CHECKPOINT AND IT + * IS WAITING FOR ACTIVE OPERATIONS TO BE COMPLETED WITH THE + * CURRENT PHASE, THEN IT IS CHECKED WHETHER THE + * LAST ACTIVE OPERATION WAS NOW COMPLETED. + * ------------------------------------------------------------------- */ + if (regFragPtr->activeList == RNIL) { + jam(); + /* ------------------------------------------------------------------ + * ACTIVE LIST ON FRAGMENT IS EMPTY AND WE ARE WAITING FOR + * THIS TO HAPPEN. + * WE WILL NOW START THE CHECKPOINT IN TUP AND ACC. + * ----------------------------------------------------------------- */ + /* SEND START LOCAL CHECKPOINT TO ACC AND TUP */ + /* ----------------------------------------------------------------- */ + fragptr.p->lcpRef = RNIL; + lcpPtr.p->lcpState = LcpRecord::LCP_START_CHKP; + sendStartLcp(signal); + }//if + }//if +}//Dblqh::releaseActiveFrag() + +/* ######################################################################### */ +/* ####### TRANSACTION MODULE ####### */ +/* THIS MODULE HANDLES THE COMMIT AND THE COMPLETE PHASE. */ +/* ######################################################################### */ +void Dblqh::warningReport(Signal* signal, int place) +{ + switch (place) { + case 0: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMMIT in wrong state in Dblqh" << endl; +#endif + break; + case 1: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMMIT with wrong transid in Dblqh" << endl; +#endif + break; + case 2: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMPLETE in wrong state in Dblqh" << endl; +#endif + break; + case 3: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMPLETE with wrong transid in Dblqh" << endl; +#endif + break; + case 4: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMMITREQ in wrong state in Dblqh" << endl; +#endif + break; + case 5: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMMITREQ with wrong transid in Dblqh" << endl; +#endif + break; + case 6: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMPLETEREQ in wrong state in Dblqh" << endl; +#endif + break; + case 7: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMPLETEREQ with wrong transid in Dblqh" << endl; +#endif + break; + case 8: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received ABORT with non-existing transid in Dblqh" << endl; +#endif + break; + case 9: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received ABORTREQ with non-existing transid in Dblqh" << endl; +#endif + break; + case 10: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received ABORTREQ in wrong state in Dblqh" << endl; +#endif + break; + case 11: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMMIT when tc-rec released in Dblqh" << endl; +#endif + break; + case 12: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received COMPLETE when tc-rec released in Dblqh" << endl; +#endif + break; + case 13: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received LQHKEYREF when tc-rec released in Dblqh" << endl; +#endif + break; + case 14: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received LQHKEYREF with wrong transid in Dblqh" << endl; +#endif + break; + case 15: + jam(); +#ifdef ABORT_TRACE + ndbout << "W: Received LQHKEYREF when already aborting in Dblqh" << endl; +#endif + break; + case 16: + jam(); + ndbrequire(cstartPhase == ZNIL); +#ifdef ABORT_TRACE + ndbout << "W: Received LQHKEYREF in wrong state in Dblqh" << endl; +#endif + break; + default: + jam(); + break; + }//switch + return; +}//Dblqh::warningReport() + +void Dblqh::errorReport(Signal* signal, int place) +{ + switch (place) { + case 0: + jam(); + break; + case 1: + jam(); + break; + case 2: + jam(); + break; + case 3: + jam(); + break; + default: + jam(); + break; + }//switch + systemErrorLab(signal); + return; +}//Dblqh::errorReport() + +/* ************************************************************************>> + * COMMIT: Start commit request from TC. This signal is originally sent as a + * packed signal and this function is called from execPACKED_SIGNAL. + * This is the normal commit protocol where TC first send this signal to the + * backup node which then will send COMMIT to the primary node. If + * everything is ok the primary node send COMMITTED back to TC. + * ************************************************************************>> */ +void Dblqh::execCOMMIT(Signal* signal) +{ + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + Uint32 tcIndex = signal->theData[0]; + Uint32 gci = signal->theData[1]; + Uint32 transid1 = signal->theData[2]; + Uint32 transid2 = signal->theData[3]; + jamEntry(); + if (tcIndex >= ttcConnectrecFileSize) { + errorReport(signal, 0); + return; + }//if + if (ERROR_INSERTED(5011)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000, 4); + return; + }//if + if (ERROR_INSERTED(5012)) { + SET_ERROR_INSERT_VALUE(5017); + sendSignalWithDelay(cownref, GSN_COMMIT, signal, 2000, 4); + return; + }//if + tcConnectptr.i = tcIndex; + ptrAss(tcConnectptr, regTcConnectionrec); + if ((tcConnectptr.p->transid[0] == transid1) && + (tcConnectptr.p->transid[1] == transid2)) { + commitReqLab(signal, gci); + return; + }//if + warningReport(signal, 1); + return; +}//Dblqh::execCOMMIT() + +/* ************************************************************************>> + * COMMITREQ: Commit request from TC. This is the commit protocol used if + * one of the nodes is not behaving correctly. TC explicitly sends COMMITREQ + * to both the backup and primary node and gets a COMMITCONF back if the + * COMMIT was ok. + * ************************************************************************>> */ +void Dblqh::execCOMMITREQ(Signal* signal) +{ + jamEntry(); + Uint32 reqPtr = signal->theData[0]; + BlockReference reqBlockref = signal->theData[1]; + Uint32 gci = signal->theData[2]; + Uint32 transid1 = signal->theData[3]; + Uint32 transid2 = signal->theData[4]; + Uint32 tcOprec = signal->theData[6]; + if (ERROR_INSERTED(5004)) { + systemErrorLab(signal); + } + if (ERROR_INSERTED(5017)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_COMMITREQ, signal, 2000, 7); + return; + }//if + if (findTransaction(transid1, + transid2, + tcOprec) != ZOK) { + warningReport(signal, 5); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + switch (regTcPtr->transactionState) { + case TcConnectionrec::PREPARED: + case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: + case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL: + jam(); +/*-------------------------------------------------------*/ +/* THE NORMAL CASE. */ +/*-------------------------------------------------------*/ + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + commitReqLab(signal, gci); + return; + break; + case TcConnectionrec::COMMITTED: + jam(); +/*---------------------------------------------------------*/ +/* FOR SOME REASON THE COMMIT PHASE HAVE BEEN */ +/* FINISHED AFTER A TIME OUT. WE NEED ONLY SEND A */ +/* COMMITCONF SIGNAL. */ +/*---------------------------------------------------------*/ + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + signal->theData[0] = regTcPtr->reqRef; + signal->theData[1] = cownNodeid; + signal->theData[2] = regTcPtr->transid[0]; + signal->theData[3] = regTcPtr->transid[1]; + sendSignal(regTcPtr->reqBlockref, GSN_COMMITCONF, signal, 4, JBB); + break; + case TcConnectionrec::COMMIT_STOPPED: + jam(); + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + /*empty*/; + break; + default: + jam(); + warningReport(signal, 4); + return; + break; + }//switch + return; +}//Dblqh::execCOMMITREQ() + +/* ************************************************************************>> + * COMPLETE : Complete the transaction. Sent as a packed signal from TC. + * Works the same way as COMMIT protocol. This is the normal case with both + * primary and backup working (See COMMIT). + * ************************************************************************>> */ +void Dblqh::execCOMPLETE(Signal* signal) +{ + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + Uint32 tcIndex = signal->theData[0]; + Uint32 transid1 = signal->theData[1]; + Uint32 transid2 = signal->theData[2]; + jamEntry(); + if (tcIndex >= ttcConnectrecFileSize) { + errorReport(signal, 1); + return; + }//if + if (ERROR_INSERTED(5013)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3); + return; + }//if + if (ERROR_INSERTED(5014)) { + SET_ERROR_INSERT_VALUE(5018); + sendSignalWithDelay(cownref, GSN_COMPLETE, signal, 2000, 3); + return; + }//if + tcConnectptr.i = tcIndex; + ptrAss(tcConnectptr, regTcConnectionrec); + if ((tcConnectptr.p->transactionState == TcConnectionrec::COMMITTED) && + (tcConnectptr.p->transid[0] == transid1) && + (tcConnectptr.p->transid[1] == transid2)) { + if (tcConnectptr.p->seqNoReplica != 0) { + jam(); + localCommitLab(signal); + return; + } else { + jam(); + completeTransLastLab(signal); + return; + }//if + }//if + if (tcConnectptr.p->transactionState != TcConnectionrec::COMMITTED) { + warningReport(signal, 2); + } else { + warningReport(signal, 3); + }//if +}//Dblqh::execCOMPLETE() + +/* ************************************************************************>> + * COMPLETEREQ: Complete request from TC. Same as COMPLETE but used if one + * node is not working ok (See COMMIT). + * ************************************************************************>> */ +void Dblqh::execCOMPLETEREQ(Signal* signal) +{ + jamEntry(); + Uint32 reqPtr = signal->theData[0]; + BlockReference reqBlockref = signal->theData[1]; + Uint32 transid1 = signal->theData[2]; + Uint32 transid2 = signal->theData[3]; + Uint32 tcOprec = signal->theData[5]; + if (ERROR_INSERTED(5005)) { + systemErrorLab(signal); + } + if (ERROR_INSERTED(5018)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_COMPLETEREQ, signal, 2000, 6); + return; + }//if + if (findTransaction(transid1, + transid2, + tcOprec) != ZOK) { + jam(); +/*---------------------------------------------------------*/ +/* FOR SOME REASON THE COMPLETE PHASE STARTED AFTER */ +/* A TIME OUT. THE TRANSACTION IS GONE. WE NEED TO */ +/* REPORT COMPLETION ANYWAY. */ +/*---------------------------------------------------------*/ + signal->theData[0] = reqPtr; + signal->theData[1] = cownNodeid; + signal->theData[2] = transid1; + signal->theData[3] = transid2; + sendSignal(reqBlockref, GSN_COMPLETECONF, signal, 4, JBB); + warningReport(signal, 7); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + switch (regTcPtr->transactionState) { + case TcConnectionrec::COMMITTED: + jam(); + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + /*empty*/; + break; +/*---------------------------------------------------------*/ +/* THE NORMAL CASE. */ +/*---------------------------------------------------------*/ + case TcConnectionrec::COMMIT_STOPPED: + jam(); +/*---------------------------------------------------------*/ +/* FOR SOME REASON THE COMPLETE PHASE STARTED AFTER */ +/* A TIME OUT. WE HAVE SET THE PROPER VARIABLES SUCH */ +/* THAT A COMPLETECONF WILL BE SENT WHEN COMPLETE IS */ +/* FINISHED. */ +/*---------------------------------------------------------*/ + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + return; + break; + default: + jam(); + warningReport(signal, 6); + return; + break; + }//switch + if (regTcPtr->seqNoReplica != 0) { + jam(); + localCommitLab(signal); + return; + } else { + jam(); + completeTransLastLab(signal); + return; + }//if +}//Dblqh::execCOMPLETEREQ() + +/* ************> */ +/* COMPLETED > */ +/* ************> */ +void Dblqh::execLQHKEYCONF(Signal* signal) +{ + LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); + Uint32 tcIndex = lqhKeyConf->opPtr; + Uint32 ttcConnectrecFileSize = ctcConnectrecFileSize; + TcConnectionrec *regTcConnectionrec = tcConnectionrec; + jamEntry(); + if (tcIndex >= ttcConnectrecFileSize) { + errorReport(signal, 2); + return; + }//if + tcConnectptr.i = tcIndex; + ptrAss(tcConnectptr, regTcConnectionrec); + switch (tcConnectptr.p->connectState) { + case TcConnectionrec::LOG_CONNECTED: + jam(); + completedLab(signal); + return; + break; + case TcConnectionrec::COPY_CONNECTED: + jam(); + copyCompletedLab(signal); + return; + break; + default: + jam(); + ndbrequire(false); + break; + }//switch + return; +}//Dblqh::execLQHKEYCONF() + +/* ------------------------------------------------------------------------- */ +/* ------- COMMIT PHASE ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::commitReqLab(Signal* signal, Uint32 gci) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState; + TcConnectionrec::TransactionState transState = regTcPtr->transactionState; + regTcPtr->gci = gci; + if (transState == TcConnectionrec::PREPARED) { + if (logWriteState == TcConnectionrec::WRITTEN) { + jam(); + regTcPtr->transactionState = TcConnectionrec::PREPARED_RECEIVED_COMMIT; + TcConnectionrecPtr saveTcPtr = tcConnectptr; + Uint32 blockNo = refToBlock(regTcPtr->tcTupBlockref); + signal->theData[0] = regTcPtr->tupConnectrec; + signal->theData[1] = gci; + EXECUTE_DIRECT(blockNo, GSN_TUP_WRITELOG_REQ, signal, 2); + jamEntry(); + if (regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_QUEUED) { + jam(); + return; + }//if + ndbrequire(regTcPtr->transactionState == TcConnectionrec::LOG_COMMIT_WRITTEN); + tcConnectptr = saveTcPtr; + } else if (logWriteState == TcConnectionrec::NOT_STARTED) { + jam(); + } else if (logWriteState == TcConnectionrec::NOT_WRITTEN) { + jam(); +/*---------------------------------------------------------------------------*/ +/* IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE. THIS CAN OCCUR */ +/* WHEN WE ARE STARTING A NEW FRAGMENT. */ +/*---------------------------------------------------------------------------*/ + regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; + } else { + ndbrequire(logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT); + jam(); +/*---------------------------------------------------------------------------*/ +/* THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER A SCAN OF ALL */ +/* OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT. THIS INDICATES THAT WE */ +/* ARE WAITING FOR THIS OPERATION TO COMMIT OR ABORT SO THAT WE CAN FIND THE */ +/* STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT. */ +/*---------------------------------------------------------------------------*/ + checkScanTcCompleted(signal); + }//if + } else if (transState == TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL) { + jam(); + regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED; + return; + } else if (transState == TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL) { + jam(); + } else { + warningReport(signal, 0); + return; + }//if + if (regTcPtr->seqNoReplica != 0) { + jam(); + commitReplyLab(signal); + return; + }//if + localCommitLab(signal); + return; +}//Dblqh::commitReqLab() + +void Dblqh::execLQH_WRITELOG_REQ(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Uint32 gci = signal->theData[1]; + Uint32 newestGci = cnewestGci; + TcConnectionrec::LogWriteState logWriteState = regTcPtr->logWriteState; + TcConnectionrec::TransactionState transState = regTcPtr->transactionState; + regTcPtr->gci = gci; + if (gci > newestGci) { + jam(); +/* ------------------------------------------------------------------------- */ +/* KEEP TRACK OF NEWEST GLOBAL CHECKPOINT THAT LQH HAS HEARD OF. */ +/* ------------------------------------------------------------------------- */ + cnewestGci = gci; + }//if + if (logWriteState == TcConnectionrec::WRITTEN) { +/*---------------------------------------------------------------------------*/ +/* I NEED TO INSERT A COMMIT LOG RECORD SINCE WE ARE WRITING LOG IN THIS */ +/* TRANSACTION. */ +/*---------------------------------------------------------------------------*/ + jam(); + LogPartRecordPtr regLogPartPtr; + Uint32 noOfLogPages = cnoOfLogPages; + jam(); + regLogPartPtr.i = regTcPtr->hashValue & 3; + ptrCheckGuard(regLogPartPtr, clogPartFileSize, logPartRecord); + if ((regLogPartPtr.p->logPartState == LogPartRecord::ACTIVE) || + (noOfLogPages == 0)) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS LOG PART WAS CURRENTLY ACTIVE WRITING ANOTHER LOG RECORD. WE MUST */ +/* WAIT UNTIL THIS PART HAS COMPLETED ITS OPERATION. */ +/*---------------------------------------------------------------------------*/ +// We must delay the write of commit info to the log to safe-guard against +// a crash due to lack of log pages. We temporary stop all log writes to this +// log part to ensure that we don't get a buffer explosion in the delayed +// signal buffer instead. +/*---------------------------------------------------------------------------*/ + linkWaitLog(signal, regLogPartPtr); + if (transState == TcConnectionrec::PREPARED) { + jam(); + regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL; + } else { + jam(); + ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT); + regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_QUEUED; + }//if + if (regLogPartPtr.p->logPartState == LogPartRecord::IDLE) { + jam(); + regLogPartPtr.p->logPartState = LogPartRecord::ACTIVE; + }//if + return; + }//if + writeCommitLog(signal, regLogPartPtr); + if (transState == TcConnectionrec::PREPARED) { + jam(); + regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL; + } else { + jam(); + ndbrequire(transState == TcConnectionrec::PREPARED_RECEIVED_COMMIT); + regTcPtr->transactionState = TcConnectionrec::LOG_COMMIT_WRITTEN; + }//if + }//if +}//Dblqh::execLQH_WRITELOG_REQ() + +void Dblqh::localCommitLab(Signal* signal) +{ + FragrecordPtr regFragptr; + regFragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + Fragrecord::FragStatus status = regFragptr.p->fragStatus; + fragptr = regFragptr; + switch (status) { + case Fragrecord::FSACTIVE: + case Fragrecord::CRASH_RECOVERING: + case Fragrecord::ACTIVE_CREATION: + jam(); + commitContinueAfterBlockedLab(signal); + return; + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::COMMIT_STOPPED; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + break; + }//switch +}//Dblqh::localCommitLab() + +void Dblqh::commitContinueAfterBlockedLab(Signal* signal) +{ +/* ------------------------------------------------------------------------- */ +/*INPUT: TC_CONNECTPTR ACTIVE OPERATION RECORD */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/*CONTINUE HERE AFTER BEING BLOCKED FOR A WHILE DURING LOCAL CHECKPOINT. */ +/*The operation is already removed from the active list since there is no */ +/*chance for any real-time breaks before we need to release it. */ +/* ------------------------------------------------------------------------- */ +/*ALSO AFTER NORMAL PROCEDURE WE CONTINUE */ +/*WE MUST COMMIT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN AND SEES A */ +/*DIRTY STATE IN TUP. */ +/* ------------------------------------------------------------------------- */ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Fragrecord * const regFragptr = fragptr.p; + Uint32 operation = regTcPtr->operation; + Uint32 simpleRead = regTcPtr->simpleRead; + Uint32 dirtyOp = regTcPtr->dirtyOp; + 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); + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } else { + if(!dirtyOp){ + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } + } + jamEntry(); + if (simpleRead) { + 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 seqNoReplica = regTcPtr->seqNoReplica; + if (regTcPtr->gci > regFragptr->newestGci) { + jam(); +/* ------------------------------------------------------------------------- */ +/*IT IS THE FIRST TIME THIS GLOBAL CHECKPOINT IS INVOLVED IN UPDATING THIS */ +/*FRAGMENT. UPDATE THE VARIABLE THAT KEEPS TRACK OF NEWEST GCI IN FRAGMENT */ +/* ------------------------------------------------------------------------- */ + regFragptr->newestGci = regTcPtr->gci; + }//if + if (dirtyOp != ZTRUE) { + if (seqNoReplica != 0) { + jam(); + completeTransNotLastLab(signal); + return; + }//if + commitReplyLab(signal); + return; + } else { +/* ------------------------------------------------------------------------- */ +/*WE MUST HANDLE DIRTY WRITES IN A SPECIAL WAY. THESE OPERATIONS WILL NOT */ +/*SEND ANY COMMIT OR COMPLETE MESSAGES TO OTHER NODES. THEY WILL MERELY SEND */ +/*THOSE SIGNALS INTERNALLY. */ +/* ------------------------------------------------------------------------- */ + if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { + jam(); + packLqhkeyreqLab(signal); + } else { + ndbrequire(regTcPtr->abortState != TcConnectionrec::NEW_FROM_TC); + jam(); + sendLqhTransconf(signal, LqhTransConf::Committed); + cleanUp(signal); + }//if + }//if +}//Dblqh::commitContinueAfterBlockedLab() + +void Dblqh::commitReplyLab(Signal* signal) +{ +/* -------------------------------------------------------------- */ +/* BACKUP AND STAND-BY REPLICAS ONLY UPDATE THE TRANSACTION STATE */ +/* -------------------------------------------------------------- */ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + TcConnectionrec::AbortState abortState = regTcPtr->abortState; + regTcPtr->transactionState = TcConnectionrec::COMMITTED; + if (abortState == TcConnectionrec::ABORT_IDLE) { + Uint32 clientBlockref = regTcPtr->clientBlockref; + if (regTcPtr->seqNoReplica == 0) { + jam(); + sendCommittedTc(signal, clientBlockref); + return; + } else { + jam(); + sendCommitLqh(signal, clientBlockref); + return; + }//if + } else if (regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC) { + jam(); + signal->theData[0] = regTcPtr->reqRef; + signal->theData[1] = cownNodeid; + signal->theData[2] = regTcPtr->transid[0]; + signal->theData[3] = regTcPtr->transid[1]; + sendSignal(tcConnectptr.p->reqBlockref, GSN_COMMITCONF, signal, 4, JBB); + } else { + ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); + jam(); + sendLqhTransconf(signal, LqhTransConf::Committed); + }//if + return; +}//Dblqh::commitReplyLab() + +/* ------------------------------------------------------------------------- */ +/* ------- COMPLETE PHASE ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::completeTransNotLastLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { + Uint32 clientBlockref = regTcPtr->clientBlockref; + jam(); + sendCompleteLqh(signal, clientBlockref); + cleanUp(signal); + return; + } else { + jam(); + completeUnusualLab(signal); + return; + }//if +}//Dblqh::completeTransNotLastLab() + +void Dblqh::completeTransLastLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { + Uint32 clientBlockref = regTcPtr->clientBlockref; + jam(); +/* ------------------------------------------------------------------------- */ +/*DIRTY WRITES WHICH ARE LAST IN THE CHAIN OF REPLICAS WILL SEND COMPLETED */ +/*INSTEAD OF SENDING PREPARED TO THE TC (OR OTHER INITIATOR OF OPERATION). */ +/* ------------------------------------------------------------------------- */ + sendCompletedTc(signal, clientBlockref); + cleanUp(signal); + return; + } else { + jam(); + completeUnusualLab(signal); + return; + }//if +}//Dblqh::completeTransLastLab() + +void Dblqh::completeUnusualLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) { + jam(); + sendAborted(signal); + } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { + jam(); + sendLqhTransconf(signal, LqhTransConf::Committed); + } else { + ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC); + jam(); + signal->theData[0] = regTcPtr->reqRef; + signal->theData[1] = cownNodeid; + signal->theData[2] = regTcPtr->transid[0]; + signal->theData[3] = regTcPtr->transid[1]; + sendSignal(regTcPtr->reqBlockref, + GSN_COMPLETECONF, signal, 4, JBB); + }//if + cleanUp(signal); + return; +}//Dblqh::completeUnusualLab() + +/* ========================================================================= */ +/* ======= RELEASE TC CONNECT RECORD ======= */ +/* */ +/* RELEASE A TC CONNECT RECORD TO THE FREELIST. */ +/* ========================================================================= */ +void Dblqh::releaseTcrec(Signal* signal, TcConnectionrecPtr locTcConnectptr) +{ + jam(); + locTcConnectptr.p->tcTimer = 0; + locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; + locTcConnectptr.p->nextTcConnectrec = cfirstfreeTcConrec; + cfirstfreeTcConrec = locTcConnectptr.i; + + TablerecPtr tabPtr; + tabPtr.i = locTcConnectptr.p->tableref; + if(tabPtr.i == RNIL) + return; + + ptrCheckGuard(tabPtr, ctabrecFileSize, tablerec); + + /** + * Normal case + */ + ndbrequire(tabPtr.p->usageCount > 0); + tabPtr.p->usageCount--; +}//Dblqh::releaseTcrec() + +void Dblqh::releaseTcrecLog(Signal* signal, TcConnectionrecPtr locTcConnectptr) +{ + jam(); + locTcConnectptr.p->tcTimer = 0; + locTcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; + locTcConnectptr.p->nextTcConnectrec = cfirstfreeTcConrec; + cfirstfreeTcConrec = locTcConnectptr.i; + + TablerecPtr tabPtr; + tabPtr.i = locTcConnectptr.p->tableref; + if(tabPtr.i == RNIL) + return; + +}//Dblqh::releaseTcrecLog() + +/* ------------------------------------------------------------------------- */ +/* ------- ABORT PHASE ------- */ +/* */ +/*THIS PART IS USED AT ERRORS THAT CAUSE ABORT OF TRANSACTION. */ +/* ------------------------------------------------------------------------- */ +/* ***************************************************>> */ +/* ABORT: Abort transaction in connection. Sender TC. */ +/* This is the normal protocol (See COMMIT) */ +/* ***************************************************>> */ +void Dblqh::execABORT(Signal* signal) +{ + jamEntry(); + Uint32 tcOprec = signal->theData[0]; + BlockReference tcBlockref = signal->theData[1]; + Uint32 transid1 = signal->theData[2]; + Uint32 transid2 = signal->theData[3]; + CRASH_INSERTION(5003); + if (ERROR_INSERTED(5015)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_ABORT, signal, 2000, 4); + return; + }//if + if (findTransaction(transid1, + transid2, + tcOprec) != ZOK) { + jam(); + + if(ERROR_INSERTED(5039) && + refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ + jam(); + SET_ERROR_INSERT_VALUE(5040); + return; + } + + if(ERROR_INSERTED(5040) && + refToNode(signal->getSendersBlockRef()) != getOwnNodeId()){ + jam(); + SET_ERROR_INSERT_VALUE(5003); + return; + } + +/* ------------------------------------------------------------------------- */ +// SEND ABORTED EVEN IF NOT FOUND. +//THE TRANSACTION MIGHT NEVER HAVE ARRIVED HERE. +/* ------------------------------------------------------------------------- */ + signal->theData[0] = tcOprec; + signal->theData[1] = transid1; + signal->theData[2] = transid2; + signal->theData[3] = cownNodeid; + signal->theData[4] = ZTRUE; + sendSignal(tcBlockref, GSN_ABORTED, signal, 5, JBB); + warningReport(signal, 8); + return; + }//if +/* ------------------------------------------------------------------------- */ +/*A GUIDING DESIGN PRINCIPLE IN HANDLING THESE ERROR SITUATIONS HAVE BEEN */ +/*KEEP IT SIMPLE. THUS WE RATHER INSERT A WAIT AND SET THE ABORT_STATE TO */ +/*ACTIVE RATHER THAN WRITE NEW CODE TO HANDLE EVERY SPECIAL SITUATION. */ +/* ------------------------------------------------------------------------- */ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->nextReplica != ZNIL) { +/* ------------------------------------------------------------------------- */ +// We will immediately send the ABORT message also to the next LQH node in line. +/* ------------------------------------------------------------------------- */ + BlockReference TLqhRef = calcLqhBlockRef(regTcPtr->nextReplica); + signal->theData[0] = regTcPtr->tcOprec; + signal->theData[1] = regTcPtr->tcBlockref; + signal->theData[2] = regTcPtr->transid[0]; + signal->theData[3] = regTcPtr->transid[1]; + sendSignal(TLqhRef, GSN_ABORT, signal, 4, JBB); + }//if + regTcPtr->abortState = TcConnectionrec::ABORT_FROM_TC; + regTcPtr->activeCreat = ZFALSE; + + const Uint32 commitAckMarker = regTcPtr->commitAckMarker; + if(commitAckMarker != RNIL){ + jam(); +#ifdef MARKER_TRACE + { + CommitAckMarkerPtr tmp; + m_commitAckMarkerHash.getPtr(tmp, commitAckMarker); + ndbout_c("Ab2 marker[%.8x %.8x]", tmp.p->transid1, tmp.p->transid2); + } +#endif + m_commitAckMarkerHash.release(commitAckMarker); + regTcPtr->commitAckMarker = RNIL; + } + + abortStateHandlerLab(signal); + + return; +}//Dblqh::execABORT() + +/* ************************************************************************>> + * ABORTREQ: Same as ABORT but used in case one node isn't working ok. + * (See COMMITREQ) + * ************************************************************************>> */ +void Dblqh::execABORTREQ(Signal* signal) +{ + jamEntry(); + Uint32 reqPtr = signal->theData[0]; + BlockReference reqBlockref = signal->theData[1]; + Uint32 transid1 = signal->theData[2]; + Uint32 transid2 = signal->theData[3]; + Uint32 tcOprec = signal->theData[5]; + if (ERROR_INSERTED(5006)) { + systemErrorLab(signal); + } + if (ERROR_INSERTED(5016)) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_ABORTREQ, signal, 2000, 6); + return; + }//if + if (findTransaction(transid1, + transid2, + tcOprec) != ZOK) { + signal->theData[0] = reqPtr; + signal->theData[2] = cownNodeid; + signal->theData[3] = transid1; + signal->theData[4] = transid2; + sendSignal(reqBlockref, GSN_ABORTCONF, signal, 5, JBB); + warningReport(signal, 9); + return; + }//if + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->transactionState != TcConnectionrec::PREPARED) { + warningReport(signal, 10); + return; + }//if + regTcPtr->reqBlockref = reqBlockref; + regTcPtr->reqRef = reqPtr; + regTcPtr->abortState = TcConnectionrec::REQ_FROM_TC; + regTcPtr->activeCreat = ZFALSE; + abortCommonLab(signal); + return; +}//Dblqh::execABORTREQ() + +/* ************>> */ +/* ACC_TO_REF > */ +/* ************>> */ +void Dblqh::execACC_TO_REF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + releaseActiveFrag(signal); + abortErrorLab(signal); + return; +}//Dblqh::execACC_TO_REF() + +/* ************> */ +/* ACCKEYREF > */ +/* ************> */ +void Dblqh::execACCKEYREF(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + terrorCode = signal->theData[1]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + TcConnectionrec * const tcPtr = tcConnectptr.p; + switch (tcPtr->transactionState) { + case TcConnectionrec::WAIT_ACC: + jam(); + releaseActiveFrag(signal); + break; + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::ABORT_STOPPED: + case TcConnectionrec::ABORT_QUEUED: + jam(); +/* ------------------------------------------------------------------------- */ +/*IGNORE SINCE ABORT OF THIS OPERATION IS ONGOING ALREADY. */ +/* ------------------------------------------------------------------------- */ + return; + break; + default: + ndbrequire(false); + break; + }//switch + const Uint32 errCode = terrorCode; + tcPtr->errorCode = errCode; +/* ------------------------------------------------------------------------- */ +/*WHEN AN ABORT FROM TC ARRIVES IT COULD ACTUALLY BE A CORRECT BEHAVIOUR */ +/*SINCE THE TUPLE MIGHT NOT HAVE ARRIVED YET OR ALREADY HAVE BEEN INSERTED. */ +/* ------------------------------------------------------------------------- */ + if (tcPtr->activeCreat == ZTRUE) { + jam(); +/* ------------------------------------------------------------------------- */ +/*THIS IS A NORMAL EVENT DURING CREATION OF A FRAGMENT. PERFORM ABORT IN */ +/*TUP AND ACC AND THEN CONTINUE WITH NORMAL COMMIT PROCESSING. IF THE ERROR */ +/*HAPPENS TO BE A SERIOUS ERROR THEN PERFORM ABORT PROCESSING AS NORMAL. */ +/* ------------------------------------------------------------------------- */ + switch (tcPtr->operation) { + case ZUPDATE: + case ZDELETE: + jam(); + if (errCode != ZNO_TUPLE_FOUND) { + jam(); +/* ------------------------------------------------------------------------- */ +/*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ +/*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ +/* ------------------------------------------------------------------------- */ + tcPtr->activeCreat = ZFALSE; + }//if + break; + case ZINSERT: + jam(); + if (errCode != ZTUPLE_ALREADY_EXIST) { + jam(); +/* ------------------------------------------------------------------------- */ +/*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ +/*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ +/* ------------------------------------------------------------------------- */ + tcPtr->activeCreat = ZFALSE; + }//if + break; + default: + jam(); +/* ------------------------------------------------------------------------- */ +/*A NORMAL ERROR WILL BE TREATED AS A NORMAL ABORT AND WILL ABORT THE */ +/*TRANSACTION. NO SPECIAL HANDLING IS NEEDED. */ +/* ------------------------------------------------------------------------- */ + tcPtr->activeCreat = ZFALSE; + break; + }//switch + } else { + /** + * Only primary replica can get ZTUPLE_ALREADY_EXIST || ZNO_TUPLE_FOUND + * + * Unless it's a simple or dirty read + * + * NOT TRUE! + * 1) op1 - primary insert ok + * 2) op1 - backup insert fail (log full or what ever) + * 3) op1 - delete ok @ primary + * 4) op1 - delete fail @ backup + * + * -> ZNO_TUPLE_FOUND is possible + */ + ndbrequire + (tcPtr->seqNoReplica == 0 || + errCode != ZTUPLE_ALREADY_EXIST || + (tcPtr->operation == ZREAD && (tcPtr->dirtyOp || tcPtr->opSimple))); + } + tcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; + abortCommonLab(signal); + return; +}//Dblqh::execACCKEYREF() + +void Dblqh::localAbortStateHandlerLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->abortState != TcConnectionrec::ABORT_IDLE) { + jam(); + return; + }//if + regTcPtr->activeCreat = ZFALSE; + regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; + regTcPtr->errorCode = terrorCode; + abortStateHandlerLab(signal); + return; +}//Dblqh::localAbortStateHandlerLab() + +void Dblqh::abortStateHandlerLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + switch (regTcPtr->transactionState) { + case TcConnectionrec::PREPARED: + jam(); +/* ------------------------------------------------------------------------- */ +/*THE OPERATION IS ALREADY PREPARED AND SENT TO THE NEXT LQH OR BACK TO TC. */ +/*WE CAN SIMPLY CONTINUE WITH THE ABORT PROCESS. */ +/*IF IT WAS A CHECK FOR TRANSACTION STATUS THEN WE REPORT THE STATUS TO THE */ +/*NEW TC AND CONTINUE WITH THE NEXT OPERATION IN LQH. */ +/* ------------------------------------------------------------------------- */ + if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { + jam(); + sendLqhTransconf(signal, LqhTransConf::Prepared); + return; + }//if + break; + case TcConnectionrec::LOG_COMMIT_WRITTEN_WAIT_SIGNAL: + case TcConnectionrec::LOG_COMMIT_QUEUED_WAIT_SIGNAL: + jam(); +/* ------------------------------------------------------------------------- */ +// We can only reach these states for multi-updates on a record in a transaction. +// We know that at least one of those has received the COMMIT signal, thus we +// declare us only prepared since we then receive the expected COMMIT signal. +/* ------------------------------------------------------------------------- */ + ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); + sendLqhTransconf(signal, LqhTransConf::Prepared); + break; + case TcConnectionrec::WAIT_TUPKEYINFO: + case TcConnectionrec::WAIT_ATTR: + jam(); +/* ------------------------------------------------------------------------- */ +/* WE ARE CURRENTLY WAITING FOR MORE INFORMATION. WE CAN START THE ABORT */ +/* PROCESS IMMEDIATELY. THE KEYINFO AND ATTRINFO SIGNALS WILL BE DROPPED */ +/* SINCE THE ABORT STATE WILL BE SET. */ +/* ------------------------------------------------------------------------- */ + break; + case TcConnectionrec::WAIT_TUP: + jam(); +/* ------------------------------------------------------------------------- */ +// TUP is currently active. We have to wait for the TUPKEYREF or TUPKEYCONF +// to arrive since we might otherwise jeopardise the local checkpoint +// consistency in overload situations. +/* ------------------------------------------------------------------------- */ + regTcPtr->transactionState = TcConnectionrec::WAIT_TUP_TO_ABORT; + return; + case TcConnectionrec::WAIT_ACC: + jam(); + if (regTcPtr->listState == TcConnectionrec::ACC_BLOCK_LIST) { + jam(); +/* ------------------------------------------------------------------------- */ +// If the operation is in the ACC Blocked list the operation is not allowed +// to start yet. We release it from the ACC Blocked list and will go through +// the gate in abortCommonLab(..) where it will be blocked. +/* ------------------------------------------------------------------------- */ + fragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + releaseAccList(signal); + } else { + jam(); +/* ------------------------------------------------------------------------- */ +// We start the abort immediately since the operation is still in the active +// list and the fragment cannot have been frozen yet. By sending LCP_HOLDOPCONF +// as direct signals we avoid the problem that we might find the operation +// in an unexpected list in ACC. +// We cannot accept being blocked before aborting ACC here since that would +// lead to seriously complex issues. +/* ------------------------------------------------------------------------- */ + abortContinueAfterBlockedLab(signal, false); + return; + }//if + break; + case TcConnectionrec::LOG_QUEUED: + jam(); +/* ------------------------------------------------------------------------- */ +/*CURRENTLY QUEUED FOR LOGGING. WAIT UNTIL THE LOG RECORD HAVE BEEN INSERTED */ +/*AND THEN CONTINUE THE ABORT PROCESS. */ +//Could also be waiting for an overloaded log disk. In this case it is easy +//to abort when CONTINUEB arrives. +/* ------------------------------------------------------------------------- */ + return; + break; + case TcConnectionrec::STOPPED: + jam(); + /* --------------------------------------------------------------------- + * WE ARE CURRENTLY QUEUED FOR ACCESS TO THE FRAGMENT BY A LCP + * Since nothing has been done, just release operation + * i.e. no prepare log record has been written + * so no abort log records needs to be written + */ + releaseWaitQueue(signal); + continueAfterLogAbortWriteLab(signal); + return; + break; + case TcConnectionrec::WAIT_AI_AFTER_ABORT: + jam(); +/* ------------------------------------------------------------------------- */ +/* ABORT OF ACC AND TUP ALREADY COMPLETED. THIS STATE IS ONLY USED WHEN */ +/* CREATING A NEW FRAGMENT. */ +/* ------------------------------------------------------------------------- */ + continueAbortLab(signal); + return; + break; + case TcConnectionrec::WAIT_TUP_TO_ABORT: + case TcConnectionrec::ABORT_STOPPED: + case TcConnectionrec::LOG_ABORT_QUEUED: + case TcConnectionrec::WAIT_ACC_ABORT: + case TcConnectionrec::ABORT_QUEUED: + jam(); +/* ------------------------------------------------------------------------- */ +/*ABORT IS ALREADY ONGOING DUE TO SOME ERROR. WE HAVE ALREADY SET THE STATE */ +/*OF THE ABORT SO THAT WE KNOW THAT TC EXPECTS A REPORT. WE CAN THUS SIMPLY */ +/*EXIT. */ +/* ------------------------------------------------------------------------- */ + return; + break; + case TcConnectionrec::COMMIT_STOPPED: + case TcConnectionrec::LOG_COMMIT_QUEUED: + case TcConnectionrec::COMMIT_QUEUED: + jam(); +/* ------------------------------------------------------------------------- */ +/*THIS IS ONLY AN ALLOWED STATE IF A DIRTY WRITE OR SIMPLE READ IS PERFORMED.*/ +/*IF WE ARE MERELY CHECKING THE TRANSACTION STATE IT IS ALSO AN ALLOWED STATE*/ +/* ------------------------------------------------------------------------- */ + if (regTcPtr->dirtyOp == ZTRUE) { + jam(); +/* ------------------------------------------------------------------------- */ +/*COMPLETE THE DIRTY WRITE AND THEN REPORT COMPLETED BACK TO TC. SINCE IT IS */ +/*A DIRTY WRITE IT IS ALLOWED TO COMMIT EVEN IF THE TRANSACTION ABORTS. */ +/* ------------------------------------------------------------------------- */ + return; + }//if + if (regTcPtr->simpleRead) { + jam(); +/* ------------------------------------------------------------------------- */ +/*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO */ +/*ACC TO CLEAR THE LOCKS. COMPLETE THIS PROCESS AND THEN RETURN AS NORMAL. */ +/*NO DATA HAS CHANGED DUE TO THIS SIMPLE READ ANYWAY. */ +/* ------------------------------------------------------------------------- */ + return; + }//if + ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); + jam(); +/* ------------------------------------------------------------------------- */ +/*WE ARE ONLY CHECKING THE STATUS OF THE TRANSACTION. IT IS COMMITTING. */ +/*COMPLETE THE COMMIT LOCALLY AND THEN SEND REPORT OF COMMITTED TO THE NEW TC*/ +/* ------------------------------------------------------------------------- */ + return; + break; + case TcConnectionrec::COMMITTED: + jam(); + ndbrequire(regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC); +/* ------------------------------------------------------------------------- */ +/*WE ARE CHECKING TRANSACTION STATUS. REPORT COMMITTED AND CONTINUE WITH THE */ +/*NEXT OPERATION. */ +/* ------------------------------------------------------------------------- */ + sendLqhTransconf(signal, LqhTransConf::Committed); + return; + break; + default: + ndbrequire(false); +/* ------------------------------------------------------------------------- */ +/*THE STATE WAS NOT AN ALLOWED STATE ON A NORMAL OPERATION. SCANS AND COPY */ +/*FRAGMENT OPERATIONS SHOULD HAVE EXECUTED IN ANOTHER PATH. */ +/* ------------------------------------------------------------------------- */ + break; + }//switch + abortCommonLab(signal); + return; +}//Dblqh::abortStateHandlerLab() + +void Dblqh::abortErrorLab(Signal* signal) +{ + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->abortState == TcConnectionrec::ABORT_IDLE) { + jam(); + regTcPtr->abortState = TcConnectionrec::ABORT_FROM_LQH; + regTcPtr->errorCode = terrorCode; + }//if + /* ----------------------------------------------------------------------- + * ACTIVE CREATION IS RESET FOR ALL ERRORS WHICH SHOULD BE HANDLED + * WITH NORMAL ABORT HANDLING. + * ----------------------------------------------------------------------- */ + regTcPtr->activeCreat = ZFALSE; + abortCommonLab(signal); + return; +}//Dblqh::abortErrorLab() + +void Dblqh::abortCommonLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + const Uint32 commitAckMarker = regTcPtr->commitAckMarker; + if(regTcPtr->activeCreat != ZTRUE && commitAckMarker != RNIL){ + /** + * There is no NR ongoing and we have a marker + */ + jam(); +#ifdef MARKER_TRACE + { + CommitAckMarkerPtr tmp; + m_commitAckMarkerHash.getPtr(tmp, commitAckMarker); + ndbout_c("Abo marker[%.8x %.8x]", tmp.p->transid1, tmp.p->transid2); + } +#endif + m_commitAckMarkerHash.release(commitAckMarker); + regTcPtr->commitAckMarker = RNIL; + } + + fragptr.i = regTcPtr->fragmentptr; + if (fragptr.i != RNIL) { + jam(); + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + case Fragrecord::CRASH_RECOVERING: + case Fragrecord::ACTIVE_CREATION: + jam(); + linkActiveFrag(signal); + abortContinueAfterBlockedLab(signal, true); + return; + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + regTcPtr->transactionState = TcConnectionrec::ABORT_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + break; + }//switch + } else { + jam(); + continueAbortLab(signal); + }//if +}//Dblqh::abortCommonLab() + +void Dblqh::abortContinueAfterBlockedLab(Signal* signal, bool canBlock) +{ + /* ------------------------------------------------------------------------ + * INPUT: TC_CONNECTPTR ACTIVE OPERATION RECORD + * ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ + * CAN COME HERE AS RESTART AFTER BEING BLOCKED BY A LOCAL CHECKPOINT. + * ------------------------------------------------------------------------ + * ALSO AS PART OF A NORMAL ABORT WITHOUT BLOCKING. + * WE MUST ABORT TUP BEFORE ACC TO ENSURE THAT NO ONE RACES IN + * AND SEES A STATE IN TUP. + * ------------------------------------------------------------------------ */ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + fragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if ((cCommitBlocked == true) && + (fragptr.p->fragActiveStatus == ZTRUE) && + (canBlock == true) && + (regTcPtr->operation != ZREAD)) { + jam(); +/* ------------------------------------------------------------------------- */ +// TUP and/or ACC have problems in writing the undo log to disk fast enough. +// We must avoid the abort at this time and try later instead. The fragment +// is also active with a local checkpoint and this commit can generate UNDO +// log records that overflow the UNDO log buffer. +// +// In certain situations it is simply too complex to insert a wait state here +// since ACC is active and we cannot release the operation from the active +// list without causing great complexity. +/* ------------------------------------------------------------------------- */ +/*---------------------------------------------------------------------------*/ +// We must delay the write of abort info to the log to safe-guard against +// a crash due to lack of log pages. We temporary stop all log writes to this +// log part to ensure that we don't get a buffer explosion in the delayed +// signal buffer instead. +/*---------------------------------------------------------------------------*/ + releaseActiveFrag(signal); + logPartPtr.i = regTcPtr->hashValue & 3; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + linkWaitLog(signal, logPartPtr); + regTcPtr->transactionState = TcConnectionrec::ABORT_QUEUED; + if (logPartPtr.p->logPartState == LogPartRecord::IDLE) { + jam(); + logPartPtr.p->logPartState = LogPartRecord::ACTIVE; + }//if + return; + }//if + signal->theData[0] = regTcPtr->tupConnectrec; + EXECUTE_DIRECT(DBTUP, GSN_TUP_ABORTREQ, signal, 1); + regTcPtr->transactionState = TcConnectionrec::WAIT_ACC_ABORT; + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(DBACC, GSN_ACC_ABORTREQ, signal, 1); + /* ------------------------------------------------------------------------ + * We need to insert a real-time break by sending ACC_ABORTCONF through the + * job buffer to ensure that we catch any ACCKEYCONF or TUPKEYCONF or + * TUPKEYREF that are in the job buffer but not yet processed. Doing + * everything without that would race and create a state error when they + * are executed. + * ----------------------------------------------------------------------- */ + return; +}//Dblqh::abortContinueAfterBlockedLab() + +/* ******************>> */ +/* ACC_ABORTCONF > */ +/* ******************>> */ +void Dblqh::execACC_ABORTCONF(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + TcConnectionrec * const regTcPtr = tcConnectptr.p; + ndbrequire(regTcPtr->transactionState == TcConnectionrec::WAIT_ACC_ABORT); + if (regTcPtr->activeCreat == ZTRUE) { + /* ---------------------------------------------------------------------- + * A NORMAL EVENT DURING CREATION OF A FRAGMENT. WE NOW NEED TO CONTINUE + * WITH NORMAL COMMIT PROCESSING. + * ---------------------------------------------------------------------- */ + if (regTcPtr->currTupAiLen == regTcPtr->totReclenAi) { + jam(); + regTcPtr->abortState = TcConnectionrec::ABORT_IDLE; + rwConcludedLab(signal); + return; + } else { + ndbrequire(regTcPtr->currTupAiLen < regTcPtr->totReclenAi); + jam(); + releaseActiveFrag(signal); + regTcPtr->transactionState = TcConnectionrec::WAIT_AI_AFTER_ABORT; + return; + }//if + }//if + releaseActiveFrag(signal); + continueAbortLab(signal); + return; +}//Dblqh::execACC_ABORTCONF() + +void Dblqh::continueAbortLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + /* ------------------------------------------------------------------------ + * AN ERROR OCCURED IN THE ACTIVE CREATION AFTER THE ABORT PHASE. + * WE NEED TO CONTINUE WITH A NORMAL ABORT. + * ------------------------------------------------------------------------ + * ALSO USED FOR NORMAL CLEAN UP AFTER A NORMAL ABORT. + * ------------------------------------------------------------------------ + * ALSO USED WHEN NO FRAGMENT WAS SET UP ON OPERATION. + * ------------------------------------------------------------------------ */ + if (regTcPtr->logWriteState == TcConnectionrec::WRITTEN) { + jam(); + /* ---------------------------------------------------------------------- + * I NEED TO INSERT A ABORT LOG RECORD SINCE WE ARE WRITING LOG IN THIS + * TRANSACTION. + * ---------------------------------------------------------------------- */ + initLogPointers(signal); + if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { + jam(); + /* -------------------------------------------------------------------- + * A PREPARE OPERATION IS CURRENTLY WRITING IN THE LOG. + * WE MUST WAIT ON OUR TURN TO WRITE THE LOG. + * IT IS NECESSARY TO WRITE ONE LOG RECORD COMPLETELY + * AT A TIME OTHERWISE WE WILL SCRAMBLE THE LOG. + * -------------------------------------------------------------------- */ + linkWaitLog(signal, logPartPtr); + regTcPtr->transactionState = TcConnectionrec::LOG_ABORT_QUEUED; + return; + }//if + if (cnoOfLogPages == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +// We must delay the write of commit info to the log to safe-guard against +// a crash due to lack of log pages. We temporary stop all log writes to this +// log part to ensure that we don't get a buffer explosion in the delayed +// signal buffer instead. +/*---------------------------------------------------------------------------*/ + linkWaitLog(signal, logPartPtr); + regTcPtr->transactionState = TcConnectionrec::LOG_ABORT_QUEUED; + if (logPartPtr.p->logPartState == LogPartRecord::IDLE) { + jam(); + logPartPtr.p->logPartState = LogPartRecord::ACTIVE; + }//if + return; + }//if + writeAbortLog(signal); + removeLogTcrec(signal); + } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_STARTED) { + jam(); + } else if (regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN) { + jam(); + /* ------------------------------------------------------------------ + * IT IS A READ OPERATION OR OTHER OPERATION THAT DO NOT USE THE LOG. + * ------------------------------------------------------------------ */ + /* ------------------------------------------------------------------ + * THE LOG HAS NOT BEEN WRITTEN SINCE THE LOG FLAG WAS FALSE. + * THIS CAN OCCUR WHEN WE ARE STARTING A NEW FRAGMENT. + * ------------------------------------------------------------------ */ + regTcPtr->logWriteState = TcConnectionrec::NOT_STARTED; + } else { + ndbrequire(regTcPtr->logWriteState == TcConnectionrec::NOT_WRITTEN_WAIT); + jam(); + /* ---------------------------------------------------------------- + * THE STATE WAS SET TO NOT_WRITTEN BY THE OPERATION BUT LATER + * A SCAN OF ALL OPERATION RECORD CHANGED IT INTO NOT_WRITTEN_WAIT. + * THIS INDICATES THAT WE ARE WAITING FOR THIS OPERATION TO COMMIT + * OR ABORT SO THAT WE CAN FIND THE + * STARTING GLOBAL CHECKPOINT OF THIS NEW FRAGMENT. + * ---------------------------------------------------------------- */ + checkScanTcCompleted(signal); + }//if + continueAfterLogAbortWriteLab(signal); + return; +}//Dblqh::continueAbortLab() + +void Dblqh::continueAfterLogAbortWriteLab(Signal* signal) +{ + TcConnectionrec * const regTcPtr = tcConnectptr.p; + if (regTcPtr->simpleRead) { + jam(); + TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); + + tcKeyRef->connectPtr = regTcPtr->applOprec; + tcKeyRef->transId[0] = regTcPtr->transid[0]; + tcKeyRef->transId[1] = regTcPtr->transid[1]; + tcKeyRef->errorCode = regTcPtr->errorCode; + sendSignal(regTcPtr->applRef, + GSN_TCKEYREF, signal, TcKeyRef::SignalLength, JBB); + cleanUp(signal); + return; + }//if + if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_LQH) { + LqhKeyRef * const lqhKeyRef = (LqhKeyRef *)signal->getDataPtrSend(); + + jam(); + lqhKeyRef->userRef = regTcPtr->clientConnectrec; + lqhKeyRef->connectPtr = regTcPtr->tcOprec; + lqhKeyRef->errorCode = regTcPtr->errorCode; + lqhKeyRef->transId1 = regTcPtr->transid[0]; + lqhKeyRef->transId2 = regTcPtr->transid[1]; + sendSignal(regTcPtr->clientBlockref, GSN_LQHKEYREF, signal, + LqhKeyRef::SignalLength, JBB); + } else if (regTcPtr->abortState == TcConnectionrec::ABORT_FROM_TC) { + jam(); + sendAborted(signal); + } else if (regTcPtr->abortState == TcConnectionrec::NEW_FROM_TC) { + jam(); + sendLqhTransconf(signal, LqhTransConf::Aborted); + } else { + ndbrequire(regTcPtr->abortState == TcConnectionrec::REQ_FROM_TC); + jam(); + signal->theData[0] = regTcPtr->reqRef; + signal->theData[1] = tcConnectptr.i; + signal->theData[2] = cownNodeid; + signal->theData[3] = regTcPtr->transid[0]; + signal->theData[4] = regTcPtr->transid[1]; + sendSignal(regTcPtr->reqBlockref, GSN_ABORTCONF, + signal, 5, JBB); + }//if + cleanUp(signal); +}//Dblqh::continueAfterLogAbortWriteLab() + +/* ########################################################################## + * ####### MODULE TO HANDLE TC FAILURE ####### + * + * ########################################################################## */ + +/* ************************************************************************>> + * NODE_FAILREP: Node failure report. Sender Ndbcntr. Set status of failed + * node to down and reply with NF_COMPLETEREP to DIH which will report that + * LQH has completed failure handling. + * ************************************************************************>> */ +void Dblqh::execNODE_FAILREP(Signal* signal) +{ + UintR TfoundNodes = 0; + UintR TnoOfNodes; + UintR Tdata[MAX_NDB_NODES]; + Uint32 i; + + NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0]; + + TnoOfNodes = nodeFail->noOfNodes; + UintR index = 0; + for (i = 1; i < MAX_NDB_NODES; i++) { + jam(); + if(NodeBitmask::get(nodeFail->theNodes, i)){ + jam(); + Tdata[index] = i; + index++; + }//if + }//for + + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + + ndbrequire(index == TnoOfNodes); + ndbrequire(cnoOfNodes - 1 < MAX_NDB_NODES); + for (i = 0; i < TnoOfNodes; i++) { + const Uint32 nodeId = Tdata[i]; + lcpPtr.p->m_EMPTY_LCP_REQ.clear(nodeId); + + for (Uint32 j = 0; j < cnoOfNodes; j++) { + jam(); + if (cnodeData[j] == nodeId){ + jam(); + cnodeStatus[j] = ZNODE_DOWN; + + TfoundNodes++; + }//if + }//for + NFCompleteRep * const nfCompRep = (NFCompleteRep *)&signal->theData[0]; + nfCompRep->blockNo = DBLQH; + nfCompRep->nodeId = cownNodeid; + nfCompRep->failedNodeId = Tdata[i]; + sendSignal(DBDIH_REF, GSN_NF_COMPLETEREP, signal, + NFCompleteRep::SignalLength, JBB); + }//for + ndbrequire(TnoOfNodes == TfoundNodes); +}//Dblqh::execNODE_FAILREP() + +/* ************************************************************************>> + * LQH_TRANSREQ: Report status of all transactions where TC was coordinated + * by a crashed TC + * ************************************************************************>> */ +/* ************************************************************************>> + * THIS SIGNAL IS RECEIVED AFTER A NODE CRASH. + * THE NODE HAD A TC AND COORDINATED A NUMBER OF TRANSACTIONS. + * NOW THE MASTER NODE IS PICKING UP THOSE TRANSACTIONS + * TO COMPLETE THEM. EITHER ABORT THEM OR COMMIT THEM. + * ************************************************************************>> */ +void Dblqh::execLQH_TRANSREQ(Signal* signal) +{ + jamEntry(); + Uint32 newTcPtr = signal->theData[0]; + BlockReference newTcBlockref = signal->theData[1]; + Uint32 oldNodeId = signal->theData[2]; + tcNodeFailptr.i = oldNodeId; + ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); + if ((tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_TRUE) || + (tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK)) { + jam(); + tcNodeFailptr.p->lastNewTcBlockref = newTcBlockref; + /* ------------------------------------------------------------------------ + * WE HAVE RECEIVED A SIGNAL SPECIFYING THAT WE NEED TO HANDLE THE FAILURE + * OF A TC. NOW WE RECEIVE ANOTHER SIGNAL WITH THE SAME ORDER. THIS CAN + * OCCUR IF THE NEW TC FAILS. WE MUST BE CAREFUL IN THIS CASE SO THAT WE DO + * NOT START PARALLEL ACTIVITIES TRYING TO DO THE SAME THING. WE SAVE THE + * NEW BLOCK REFERENCE TO THE LAST NEW TC IN A VARIABLE AND ASSIGN TO IT TO + * NEW_TC_BLOCKREF WHEN THE OLD PROCESS RETURNS TO LQH_TRANS_NEXT. IT IS + * CERTAIN TO COME THERE SINCE THIS IS THE ONLY PATH TO TAKE CARE OF THE + * NEXT TC CONNECT RECORD. WE SET THE STATUS TO BREAK TO INDICATE TO THE OLD + * PROCESS WHAT IS HAPPENING. + * ------------------------------------------------------------------------ */ + tcNodeFailptr.p->lastNewTcRef = newTcPtr; + tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_BREAK; + return; + }//if + tcNodeFailptr.p->oldNodeId = oldNodeId; + tcNodeFailptr.p->newTcBlockref = newTcBlockref; + tcNodeFailptr.p->newTcRef = newTcPtr; + tcNodeFailptr.p->tcRecNow = 0; + tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE; + signal->theData[0] = ZLQH_TRANS_NEXT; + signal->theData[1] = tcNodeFailptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +}//Dblqh::execLQH_TRANSREQ() + +void Dblqh::lqhTransNextLab(Signal* signal) +{ + UintR tend; + UintR tstart; + UintR guard0; + + if (tcNodeFailptr.p->tcFailStatus == TcNodeFailRecord::TC_STATE_BREAK) { + jam(); + /* ---------------------------------------------------------------------- + * AN INTERRUPTION TO THIS NODE FAIL HANDLING WAS RECEIVED AND A NEW + * TC HAVE BEEN ASSIGNED TO TAKE OVER THE FAILED TC. PROBABLY THE OLD + * NEW TC HAVE FAILED. + * ---------------------------------------------------------------------- */ + tcNodeFailptr.p->newTcBlockref = tcNodeFailptr.p->lastNewTcBlockref; + tcNodeFailptr.p->newTcRef = tcNodeFailptr.p->lastNewTcRef; + tcNodeFailptr.p->tcRecNow = 0; + tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_TRUE; + }//if + tstart = tcNodeFailptr.p->tcRecNow; + tend = tstart + 200; + guard0 = tend; + for (tcConnectptr.i = tstart; tcConnectptr.i <= guard0; tcConnectptr.i++) { + jam(); + if (tcConnectptr.i >= ctcConnectrecFileSize) { + jam(); + /** + * Finished with scanning operation record + * + * now scan markers + */ + scanMarkers(signal, tcNodeFailptr.i, 0, RNIL); + return; + }//if + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) { + if (tcConnectptr.p->transactionState != TcConnectionrec::TC_NOT_CONNECTED) { + if (tcConnectptr.p->tcScanRec == RNIL) { + if (refToNode(tcConnectptr.p->tcBlockref) == tcNodeFailptr.p->oldNodeId) { + if (tcConnectptr.p->operation != ZREAD) { + jam(); + tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; + tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; + abortStateHandlerLab(signal); + return; + } else { + jam(); + if (tcConnectptr.p->opSimple != ZTRUE) { + jam(); + tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; + tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; + abortStateHandlerLab(signal); + return; + }//if + }//if + }//if + } else { + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + if (scanptr.p->scanType == ScanRecord::COPY) { + jam(); + if (scanptr.p->scanNodeId == tcNodeFailptr.p->oldNodeId) { + jam(); + /* ------------------------------------------------------------ + * THE RECEIVER OF THE COPY HAVE FAILED. + * WE HAVE TO CLOSE THE COPY PROCESS. + * ------------------------------------------------------------ */ + tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; + tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; + closeCopyRequestLab(signal); + return; + }//if + } else { + if (scanptr.p->scanType == ScanRecord::SCAN) { + jam(); + if (refToNode(tcConnectptr.p->tcBlockref) == + tcNodeFailptr.p->oldNodeId) { + jam(); + tcConnectptr.p->tcNodeFailrec = tcNodeFailptr.i; + tcConnectptr.p->abortState = TcConnectionrec::NEW_FROM_TC; + closeScanRequestLab(signal); + return; + }//if + } else { + jam(); + /* ------------------------------------------------------------ + * THIS IS AN ERROR THAT SHOULD NOT OCCUR. WE CRASH THE SYSTEM. + * ------------------------------------------------------------ */ + systemErrorLab(signal); + return; + }//if + }//if + }//if + }//if + }//if + }//for + tcNodeFailptr.p->tcRecNow = tend + 1; + signal->theData[0] = ZLQH_TRANS_NEXT; + signal->theData[1] = tcNodeFailptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +}//Dblqh::lqhTransNextLab() + +void +Dblqh::scanMarkers(Signal* signal, + Uint32 tcNodeFail, + Uint32 startBucket, + Uint32 i){ + + jam(); + + TcNodeFailRecordPtr tcNodeFailPtr; + tcNodeFailPtr.i = tcNodeFail; + ptrCheckGuard(tcNodeFailPtr, ctcNodeFailrecFileSize, tcNodeFailRecord); + const Uint32 crashedTcNodeId = tcNodeFailPtr.p->oldNodeId; + + CommitAckMarkerIterator iter; + if(i == RNIL){ + m_commitAckMarkerHash.next(startBucket, iter); + } else { + jam(); + iter.curr.i = i; + iter.bucket = startBucket; + m_commitAckMarkerHash.getPtr(iter.curr); + m_commitAckMarkerHash.next(iter); + } + + const Uint32 RT_BREAK = 256; + for(i = 0; i<RT_BREAK || iter.bucket == startBucket; i++){ + jam(); + + if(iter.curr.i == RNIL){ + /** + * Done with iteration + */ + jam(); + + tcNodeFailPtr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE; + signal->theData[0] = tcNodeFailPtr.p->newTcRef; + signal->theData[1] = cownNodeid; + signal->theData[2] = LqhTransConf::LastTransConf; + sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF, + signal, 3, JBB); + return; + } + + if(iter.curr.p->tcNodeId == crashedTcNodeId){ + jam(); + + /** + * Found marker belonging to crashed node + */ + LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0]; + lqhTransConf->tcRef = tcNodeFailPtr.p->newTcRef; + lqhTransConf->lqhNodeId = cownNodeid; + lqhTransConf->operationStatus = LqhTransConf::Marker; + lqhTransConf->transId1 = iter.curr.p->transid1; + lqhTransConf->transId2 = iter.curr.p->transid2; + lqhTransConf->apiRef = iter.curr.p->apiRef; + lqhTransConf->apiOpRec = iter.curr.p->apiOprec; + sendSignal(tcNodeFailPtr.p->newTcBlockref, GSN_LQH_TRANSCONF, + signal, 7, JBB); + + signal->theData[0] = ZSCAN_MARKERS; + signal->theData[1] = tcNodeFailPtr.i; + signal->theData[2] = iter.bucket; + signal->theData[3] = iter.curr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); + return; + } + + m_commitAckMarkerHash.next(iter); + } + + signal->theData[0] = ZSCAN_MARKERS; + signal->theData[1] = tcNodeFailPtr.i; + signal->theData[2] = iter.bucket; + signal->theData[3] = RNIL; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); +} + +/* ######################################################################### + * ####### SCAN MODULE ####### + * + * ######################################################################### + * ------------------------------------------------------------------------- + * THIS MODULE CONTAINS THE CODE THAT HANDLES A SCAN OF A PARTICULAR FRAGMENT + * IT OPERATES UNDER THE CONTROL OF TC AND ORDERS ACC TO PERFORM A SCAN OF + * ALL TUPLES IN THE FRAGMENT. TUP PERFORMS THE NECESSARY SEARCH CONDITIONS + * TO ENSURE THAT ONLY VALID TUPLES ARE RETURNED TO THE APPLICATION. + * ------------------------------------------------------------------------- */ +/* *************** */ +/* 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->scanCompletedStatus = ZTRUE; + scanptr.p->scanStoredProcId = signal->theData[2]; + tcConnectptr.p->errorCode = errorCode; + closeScanLab(signal); + break; + default: + ndbrequire(false); + }//switch +}//Dblqh::execSTORED_PROCREF() + +/* -------------------------------------------------------------------------- + * ENTER SCAN_NEXTREQ + * -------------------------------------------------------------------------- + * PRECONDITION: + * TRANSACTION_STATE = SCAN_STATE + * SCAN_STATE = WAIT_SCAN_NEXTREQ + * + * Case scanLockHold: ZTRUE = Unlock previous round of + * scanned row(s) and fetch next set of rows. + * ZFALSE = Fetch new set of rows. + * Number of rows to read depends on parallelism and how many rows + * left to scan in the fragment. SCAN_NEXTREQ can also be sent with + * closeFlag == ZTRUE to close the scan. + * ------------------------------------------------------------------------- */ +void Dblqh::execSCAN_NEXTREQ(Signal* signal) +{ + jamEntry(); + const ScanFragNextReq * const nextReq = + (ScanFragNextReq*)&signal->theData[0]; + const Uint32 transid1 = nextReq->transId1; + const Uint32 transid2 = nextReq->transId2; + const Uint32 senderData = nextReq->senderData; + + if (findTransaction(transid1, transid2, senderData) != ZOK){ + jam(); + DEBUG(senderData << + " Received SCAN_NEXTREQ in LQH with close flag when closed"); + ndbrequire(nextReq->closeFlag == ZTRUE); + return; + } + + // Crash node if signal sender is same node + CRASH_INSERTION2(5021, refToNode(signal->senderBlockRef()) == cownNodeid); + // Crash node if signal sender is NOT same node + CRASH_INSERTION2(5022, refToNode(signal->senderBlockRef()) != cownNodeid); + + if (ERROR_INSERTED(5023)){ + // Drop signal if sender is same node + if (refToNode(signal->senderBlockRef()) == cownNodeid) { + CLEAR_ERROR_INSERT_VALUE; + return; + } + }//if + if (ERROR_INSERTED(5024)){ + // Drop signal if sender is NOT same node + if (refToNode(signal->senderBlockRef()) != cownNodeid) { + CLEAR_ERROR_INSERT_VALUE; + return; + } + }//if + if (ERROR_INSERTED(5025)){ + // Delay signal if sender is NOT same node + if (refToNode(signal->senderBlockRef()) != cownNodeid) { + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_SCAN_NEXTREQ, signal, 1000, + signal->length()); + return; + } + }//if + if (ERROR_INSERTED(5030)){ + ndbout << "ERROR 5030" << endl; + CLEAR_ERROR_INSERT_VALUE; + // Drop signal + return; + }//if + + if(ERROR_INSERTED(5036)){ + return; + } + + scanptr.i = tcConnectptr.p->tcScanRec; + ndbrequire(scanptr.i != RNIL); + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanTcWaiting = ZTRUE; + + /* ------------------------------------------------------------------ + * If close flag is set this scan should be closed + * If we are waiting for SCAN_NEXTREQ set flag to stop scanning and + * continue execution else set flags and wait until the scan + * completes itself + * ------------------------------------------------------------------ */ + if (nextReq->closeFlag == ZTRUE){ + jam(); + if(ERROR_INSERTED(5034)){ + CLEAR_ERROR_INSERT_VALUE; + } + if(ERROR_INSERTED(5036)){ + CLEAR_ERROR_INSERT_VALUE; + return; + } + closeScanRequestLab(signal); + return; + }//if + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + + /** + * Change parameters while running + * (is currently not supported) + */ + const Uint32 max_rows = nextReq->batch_size_rows; + const Uint32 max_bytes = nextReq->batch_size_bytes; + ndbrequire(scanptr.p->m_max_batch_size_rows == max_rows); + ndbrequire(scanptr.p->m_max_batch_size_bytes == max_bytes); + + /* -------------------------------------------------------------------- + * If scanLockHold = TRUE we need to unlock previous round of + * scanned records. + * scanReleaseLocks will set states for this and send a NEXT_SCANREQ. + * When confirm signal NEXT_SCANCONF arrives we call + * continueScanNextReqLab to continue scanning new rows and + * acquiring new locks. + * -------------------------------------------------------------------- */ + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + + /* ----------------------------------------------------------------------- + * We end up here when scanLockHold = FALSE or no rows was locked from + * previous round. + * Simply continue scanning. + * ----------------------------------------------------------------------- */ + continueScanNextReqLab(signal); +}//Dblqh::execSCAN_NEXTREQ() + +void Dblqh::continueScanNextReqLab(Signal* signal) +{ + if (scanptr.p->scanCompletedStatus == ZTRUE) { + jam(); + closeScanLab(signal); + return; + }//if + + if(scanptr.p->m_last_row){ + jam(); + scanptr.p->scanCompletedStatus = ZTRUE; + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + return; + } + + // Update timer on tcConnectRecord + tcConnectptr.p->tcTimer = cLqhTimeOutCount; + init_acc_ptr_list(scanptr.p); + scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; + scanNextLoopLab(signal); +}//Dblqh::continueScanNextReqLab() + +/* ------------------------------------------------------------------------- + * WE NEED TO RELEASE LOCKS BEFORE CONTINUING + * ------------------------------------------------------------------------- */ +void Dblqh::scanReleaseLocksLab(Signal* signal) +{ + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_RELEASE_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + }//switch + continueScanReleaseAfterBlockedLab(signal); +}//Dblqh::scanReleaseLocksLab() + +void Dblqh::continueScanReleaseAfterBlockedLab(Signal* signal) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanState = ScanRecord::WAIT_RELEASE_LOCK; + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1]= + get_acc_ptr_from_scan_record(scanptr.p, + scanptr.p->scanReleaseCounter -1, + false); + signal->theData[2] = NextScanReq::ZSCAN_COMMIT; + if (! scanptr.p->rangeScan) + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); + else + sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); +}//Dblqh::continueScanReleaseAfterBlockedLab() + +/* ------------------------------------------------------------------------- + * ENTER SCAN_NEXTREQ + * ------------------------------------------------------------------------- + * SCAN_NEXT_REQ SIGNAL ARRIVED IN THE MIDDLE OF EXECUTION OF THE SCAN. + * IT WAS A REQUEST TO CLOSE THE SCAN. WE WILL CLOSE THE SCAN IN A + * CAREFUL MANNER TO ENSURE THAT NO ERROR OCCURS. + * ------------------------------------------------------------------------- + * PRECONDITION: + * TRANSACTION_STATE = SCAN_STATE_USED + * TSCAN_COMPLETED = ZTRUE + * ------------------------------------------------------------------------- + * WE CAN ALSO ARRIVE AT THIS LABEL AFTER A NODE CRASH OF THE SCAN + * COORDINATOR. + * ------------------------------------------------------------------------- */ +void Dblqh::closeScanRequestLab(Signal* signal) +{ + DEBUG("transactionState = " << tcConnectptr.p->transactionState); + switch (tcConnectptr.p->transactionState) { + case TcConnectionrec::SCAN_STATE_USED: + DEBUG("scanState = " << scanptr.p->scanState); + switch (scanptr.p->scanState) { + case ScanRecord::IN_QUEUE: + jam(); + tupScanCloseConfLab(signal); + break; + case ScanRecord::WAIT_NEXT_SCAN: + jam(); + /* ------------------------------------------------------------------- + * SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN. + * ------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + break; + case ScanRecord::WAIT_ACC_SCAN: + case ScanRecord::WAIT_STORED_PROC_SCAN: + jam(); + /* ------------------------------------------------------------------- + * WE ARE CURRENTLY STARTING UP THE SCAN. SET COMPLETED STATUS + * AND WAIT FOR COMPLETION OF STARTUP. + * ------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + break; + case ScanRecord::WAIT_CLOSE_SCAN: + case ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN: + jam(); + /*empty*/; + break; + /* ------------------------------------------------------------------- + * CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING. + * ------------------------------------------------------------------- */ + case ScanRecord::WAIT_RELEASE_LOCK: + jam(); + /* ------------------------------------------------------------------- + * WE ARE CURRENTLY RELEASING RECORD LOCKS. AFTER COMPLETING THIS + * WE WILL START TO CLOSE THE SCAN. + * ------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + break; + case ScanRecord::WAIT_SCAN_NEXTREQ: + jam(); + /* ------------------------------------------------------------------- + * WE ARE WAITING FOR A SCAN_NEXTREQ FROM SCAN COORDINATOR(TC) + * WICH HAVE CRASHED. CLOSE THE SCAN + * ------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + + if (scanptr.p->scanLockHold == ZTRUE) { + if (scanptr.p->m_curr_batch_size_rows > 0) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + }//if + closeScanLab(signal); + break; + default: + ndbrequire(false); + }//switch + break; + case TcConnectionrec::WAIT_SCAN_AI: + jam(); + /* --------------------------------------------------------------------- + * WE ARE STILL WAITING FOR THE ATTRIBUTE INFORMATION THAT + * OBVIOUSLY WILL NOT ARRIVE. WE CAN QUIT IMMEDIATELY HERE. + * --------------------------------------------------------------------- */ + //XXX jonas this have to be wrong... + releaseOprec(signal); + if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) { + jam(); + tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; + ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); + tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; + signal->theData[0] = ZLQH_TRANS_NEXT; + signal->theData[1] = tcNodeFailptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; + }//if + tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes= 0; + sendScanFragConf(signal, ZTRUE); + abort_scan(signal, scanptr.i, 0); + return; + break; + case TcConnectionrec::SCAN_TUPKEY: + case TcConnectionrec::SCAN_FIRST_STOPPED: + case TcConnectionrec::SCAN_CHECK_STOPPED: + case TcConnectionrec::SCAN_STOPPED: + jam(); + /* --------------------------------------------------------------------- + * SET COMPLETION STATUS AND WAIT FOR OPPORTUNITY TO STOP THE SCAN. + * --------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + break; + case TcConnectionrec::SCAN_RELEASE_STOPPED: + jam(); + /* --------------------------------------------------------------------- + * WE ARE CURRENTLY RELEASING RECORD LOCKS. AFTER COMPLETING + * THIS WE WILL START TO CLOSE THE SCAN. + * --------------------------------------------------------------------- */ + scanptr.p->scanCompletedStatus = ZTRUE; + break; + case TcConnectionrec::SCAN_CLOSE_STOPPED: + jam(); + /* --------------------------------------------------------------------- + * CLOSE IS ALREADY ONGOING. WE NEED NOT DO ANYTHING. + * --------------------------------------------------------------------- */ + /*empty*/; + break; + default: + ndbrequire(false); + }//switch +}//Dblqh::closeScanRequestLab() + +/* ------------------------------------------------------------------------- + * ENTER NEXT_SCANCONF + * ------------------------------------------------------------------------- + * PRECONDITION: SCAN_STATE = WAIT_RELEASE_LOCK + * ------------------------------------------------------------------------- */ +void Dblqh::scanLockReleasedLab(Signal* signal) +{ + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + releaseActiveFrag(signal); + + if (scanptr.p->scanReleaseCounter == scanptr.p->m_curr_batch_size_rows) { + if ((scanptr.p->scanErrorCounter > 0) || + (scanptr.p->scanCompletedStatus == ZTRUE)) { + jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; + closeScanLab(signal); + } else if (scanptr.p->check_scan_batch_completed() && + scanptr.p->scanLockHold != ZTRUE) { + jam(); + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + } else if (scanptr.p->m_last_row && !scanptr.p->scanLockHold) { + jam(); + closeScanLab(signal); + return; + } else { + jam(); + /* + * We came here after releasing locks after + * receiving SCAN_NEXTREQ from TC. We only come here + * when scanHoldLock == ZTRUE + */ + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; + continueScanNextReqLab(signal); + }//if + } else if (scanptr.p->scanReleaseCounter < scanptr.p->m_curr_batch_size_rows) { + jam(); + scanptr.p->scanReleaseCounter++; + scanReleaseLocksLab(signal); + } else { + jam(); + /* + We come here when we have been scanning for a long time and not been able + to find m_max_batch_size_rows records to return. We needed to release + the record we didn't want, but now we are returning all found records to + the API. + */ + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + }//if +}//Dblqh::scanLockReleasedLab() + +bool +Dblqh::seize_acc_ptr_list(ScanRecord* scanP, Uint32 batch_size) +{ + Uint32 i; + Uint32 attr_buf_recs= (batch_size + 30) / 32; + + if (batch_size > 1) { + if (c_no_attrinbuf_recs < attr_buf_recs) { + jam(); + return false; + } + for (i= 1; i <= attr_buf_recs; i++) { + scanP->scan_acc_op_ptr[i]= seize_attrinbuf(); + } + } + scanP->scan_acc_attr_recs= attr_buf_recs; + scanP->scan_acc_index = 0; + return true; +} + +void +Dblqh::release_acc_ptr_list(ScanRecord* scanP) +{ + Uint32 i, attr_buf_recs; + attr_buf_recs= scanP->scan_acc_attr_recs; + + for (i= 1; i <= attr_buf_recs; i++) { + release_attrinbuf(scanP->scan_acc_op_ptr[i]); + } + scanP->scan_acc_attr_recs= 0; + scanP->scan_acc_index = 0; +} + +Uint32 +Dblqh::seize_attrinbuf() +{ + AttrbufPtr regAttrPtr; + Uint32 ret_attr_buf; + ndbrequire(c_no_attrinbuf_recs > 0); + c_no_attrinbuf_recs--; + ret_attr_buf= cfirstfreeAttrinbuf; + regAttrPtr.i= ret_attr_buf; + ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); + cfirstfreeAttrinbuf= regAttrPtr.p->attrbuf[ZINBUF_NEXT]; + return ret_attr_buf; +} + +Uint32 +Dblqh::release_attrinbuf(Uint32 attr_buf_i) +{ + Uint32 next_buf; + AttrbufPtr regAttrPtr; + c_no_attrinbuf_recs++; + regAttrPtr.i= attr_buf_i; + ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); + next_buf= regAttrPtr.p->attrbuf[ZINBUF_NEXT]; + regAttrPtr.p->attrbuf[ZINBUF_NEXT]= cfirstfreeAttrinbuf; + cfirstfreeAttrinbuf= regAttrPtr.i; + return next_buf; +} + +void +Dblqh::init_acc_ptr_list(ScanRecord* scanP) +{ + scanP->scan_acc_index = 0; +} + +Uint32 +Dblqh::get_acc_ptr_from_scan_record(ScanRecord* scanP, + Uint32 index, + bool crash_flag) +{ + Uint32* acc_ptr; + Uint32 attr_buf_rec, attr_buf_index; + if (!((index < MAX_PARALLEL_OP_PER_SCAN) && + index < scanP->scan_acc_index)) { + ndbrequire(crash_flag); + return RNIL; + } + i_get_acc_ptr(scanP, acc_ptr, index); + return *acc_ptr; +} + +void +Dblqh::set_acc_ptr_in_scan_record(ScanRecord* scanP, + Uint32 index, Uint32 acc) +{ + Uint32 *acc_ptr; + ndbrequire((index == 0 || scanP->scan_acc_index == index) && + (index < MAX_PARALLEL_OP_PER_SCAN)); + scanP->scan_acc_index= index + 1; + i_get_acc_ptr(scanP, acc_ptr, index); + *acc_ptr= acc; +} + +/* ------------------------------------------------------------------------- + * SCAN_FRAGREQ: Request to start scanning the specified fragment of a table. + * ------------------------------------------------------------------------- */ +void Dblqh::execSCAN_FRAGREQ(Signal* signal) +{ + ScanFragReq * const scanFragReq = (ScanFragReq *)&signal->theData[0]; + ScanFragRef * ref; + const Uint32 transid1 = scanFragReq->transId1; + const Uint32 transid2 = scanFragReq->transId2; + Uint32 errorCode= 0; + Uint32 senderData; + Uint32 hashIndex; + TcConnectionrecPtr nextHashptr; + + jamEntry(); + const Uint32 reqinfo = scanFragReq->requestInfo; + const Uint32 fragId = (scanFragReq->fragmentNoKeyLen & 0xFFFF); + const Uint32 keyLen = (scanFragReq->fragmentNoKeyLen >> 16); + tabptr.i = scanFragReq->tableId; + const Uint32 max_rows = scanFragReq->batch_size_rows; + const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo); + const Uint8 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo); + const Uint8 rangeScan = ScanFragReq::getRangeScanFlag(reqinfo); + + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + if(tabptr.p->tableStatus != Tablerec::TABLE_DEFINED){ + senderData = scanFragReq->senderData; + goto error_handler_early_1; + } + + if (cfirstfreeTcConrec != RNIL) { + seizeTcrec(); + tcConnectptr.p->clientConnectrec = scanFragReq->senderData; + tcConnectptr.p->clientBlockref = signal->senderBlockRef(); + tcConnectptr.p->savePointId = scanFragReq->savePointId; + } else { + jam(); + /* -------------------------------------------------------------------- + * NO FREE TC RECORD AVAILABLE, THUS WE CANNOT HANDLE THE REQUEST. + * -------------------------------------------------------------------- */ + errorCode = ZNO_TC_CONNECT_ERROR; + senderData = scanFragReq->senderData; + goto error_handler_early; + }//if + /** + * A write allways have to get keyinfo + */ + ndbrequire(scanLockMode == 0 || keyinfo); + + ndbrequire(max_rows > 0 && max_rows <= MAX_PARALLEL_OP_PER_SCAN); + if (!getFragmentrec(signal, fragId)) { + errorCode = __LINE__; + goto error_handler; + }//if + + // Verify scan type vs table type (both sides are boolean) + if (rangeScan != DictTabInfo::isOrderedIndex(fragptr.p->tableType)) { + errorCode = __LINE__; // XXX fix + goto error_handler; + }//if + + // 1 scan record is reserved for node recovery + if (cscanNoFreeRec < 2) { + jam(); + errorCode = ScanFragRef::ZNO_FREE_SCANREC_ERROR; + goto error_handler; + } + + // XXX adjust cmaxAccOps for range scans and remove this comment + if ((cbookedAccOps + max_rows) > cmaxAccOps) { + jam(); + errorCode = ScanFragRef::ZSCAN_BOOK_ACC_OP_ERROR; + goto error_handler; + }//if + + ndbrequire(c_scanRecordPool.seize(scanptr)); + initScanTc(signal, + transid1, + transid2, + fragId, + ZNIL); + tcConnectptr.p->save1 = 4; + tcConnectptr.p->primKeyLen = keyLen + 4; // hard coded in execKEYINFO + errorCode = initScanrec(scanFragReq); + if (errorCode != ZOK) { + jam(); + goto error_handler2; + }//if + cscanNoFreeRec--; + cbookedAccOps += max_rows; + + hashIndex = (tcConnectptr.p->transid[0] ^ tcConnectptr.p->tcOprec) & 1023; + nextHashptr.i = ctransidHash[hashIndex]; + ctransidHash[hashIndex] = tcConnectptr.i; + tcConnectptr.p->prevHashRec = RNIL; + tcConnectptr.p->nextHashRec = nextHashptr.i; + if (nextHashptr.i != RNIL) { + jam(); + /* --------------------------------------------------------------------- + * ENSURE THAT THE NEXT RECORD HAS SET PREVIOUS TO OUR RECORD + * IF IT EXISTS + * --------------------------------------------------------------------- */ + ptrCheckGuard(nextHashptr, ctcConnectrecFileSize, tcConnectionrec); + nextHashptr.p->prevHashRec = tcConnectptr.i; + }//if + if (scanptr.p->scanAiLength > 0) { + jam(); + tcConnectptr.p->transactionState = TcConnectionrec::WAIT_SCAN_AI; + return; + }//if + continueAfterReceivingAllAiLab(signal); + return; + +error_handler2: + // no scan number allocated + c_scanRecordPool.release(scanptr); +error_handler: + ref = (ScanFragRef*)&signal->theData[0]; + tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; + ref->senderData = tcConnectptr.p->clientConnectrec; + ref->transId1 = transid1; + ref->transId2 = transid2; + ref->errorCode = errorCode; + sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, + ScanFragRef::SignalLength, JBB); + releaseOprec(signal); + releaseTcrec(signal, tcConnectptr); + return; + + error_handler_early_1: + if(tabptr.p->tableStatus == Tablerec::NOT_DEFINED){ + jam(); + errorCode = ZTABLE_NOT_DEFINED; + } else if (tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || + tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ + jam(); + errorCode = ZDROP_TABLE_IN_PROGRESS; + } else { + ndbrequire(0); + } + error_handler_early: + ref = (ScanFragRef*)&signal->theData[0]; + ref->senderData = senderData; + ref->transId1 = transid1; + ref->transId2 = transid2; + ref->errorCode = errorCode; + sendSignal(signal->senderBlockRef(), GSN_SCAN_FRAGREF, signal, + ScanFragRef::SignalLength, JBB); +}//Dblqh::execSCAN_FRAGREQ() + +void Dblqh::continueAfterReceivingAllAiLab(Signal* signal) +{ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + + if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ + jam(); + return; + } + + scanptr.p->scanState = ScanRecord::WAIT_ACC_SCAN; + AccScanReq * req = (AccScanReq*)&signal->theData[0]; + req->senderData = scanptr.i; + req->senderRef = cownref; + req->tableId = tcConnectptr.p->tableref; + req->fragmentNo = tcConnectptr.p->fragmentid; + req->requestInfo = 0; + AccScanReq::setLockMode(req->requestInfo, scanptr.p->scanLockMode); + AccScanReq::setReadCommittedFlag(req->requestInfo, scanptr.p->readCommitted); + AccScanReq::setDescendingFlag(req->requestInfo, scanptr.p->descending); + req->transId1 = tcConnectptr.p->transid[0]; + req->transId2 = tcConnectptr.p->transid[1]; + req->savePointId = tcConnectptr.p->savePointId; + // always use if-stmt to switch (instead of setting a "scan block ref") + if (! scanptr.p->rangeScan) + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_SCANREQ, signal, + AccScanReq::SignalLength, JBB); + else + sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_ACC_SCANREQ, signal, + AccScanReq::SignalLength, JBB); +}//Dblqh::continueAfterReceivingAllAiLab() + +void Dblqh::scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { + if (tcConnectptr.p->currTupAiLen < scanptr.p->scanAiLength) { + jam(); + } else { + jam(); + ndbrequire(tcConnectptr.p->currTupAiLen == scanptr.p->scanAiLength); + continueAfterReceivingAllAiLab(signal); + }//if + return; + }//if + abort_scan(signal, scanptr.i, ZGET_ATTRINBUF_ERROR); +} + +void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){ + jam(); + scanptr.i = scan_ptr_i; + c_scanRecordPool.getPtr(scanptr); + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + finishScanrec(signal); + releaseScanrec(signal); + tcConnectptr.p->transactionState = TcConnectionrec::IDLE; + tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; + + if(errcode) + { + 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 = errcode; + sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, + ScanFragRef::SignalLength, JBB); + } + deleteTransidHash(signal); + releaseOprec(signal); + releaseTcrec(signal, tcConnectptr); +} + +/*---------------------------------------------------------------------*/ +/* 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::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; + if (scanptr.p->rangeScan) { + jam(); + TuxBoundInfo* req = (TuxBoundInfo*)signal->getDataPtrSend(); + req->errorCode = RNIL; + req->tuxScanPtrI = scanptr.p->scanAccPtr; + Uint32 len = req->boundAiLength = copy_bounds(req->data, tcConnectptr.p); + EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO, signal, + TuxBoundInfo::SignalLength + len); + + jamEntry(); + if (req->errorCode != 0) { + jam(); + /* + * Cannot use STORED_PROCREF to abort since even the REF + * returns a stored proc id. So record error and continue. + * The scan is already Invalid in TUX and returns empty set. + */ + tcConnectptr.p->errorCode = req->errorCode; + } + } + + scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_SCAN; + if(scanptr.p->scanStoredProcId == RNIL) + { + jam(); + signal->theData[0] = tcConnectptr.p->tupConnectrec; + signal->theData[1] = tcConnectptr.p->tableref; + signal->theData[2] = scanptr.p->scanSchemaVersion; + signal->theData[3] = ZSTORED_PROC_SCAN; + + signal->theData[4] = scanptr.p->scanAiLength; + sendSignal(tcConnectptr.p->tcTupBlockref, + GSN_STORED_PROCREQ, signal, 5, JBB); + + signal->theData[0] = tcConnectptr.p->tupConnectrec; + AttrbufPtr regAttrinbufptr; + Uint32 firstAttr = regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf; + while (regAttrinbufptr.i != RNIL) { + ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); + jam(); + Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; + ndbrequire(dataLen != 0); + // first 3 words already set in STORED_PROCREQ + MEMCOPY_NO_WORDS(&signal->theData[3], + ®Attrinbufptr.p->attrbuf[0], + dataLen); + sendSignal(tcConnectptr.p->tcTupBlockref, + GSN_ATTRINFO, signal, dataLen + 3, JBB); + regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; + c_no_attrinbuf_recs++; + }//while + + /** + * Release attr info + */ + if(firstAttr != RNIL) + { + regAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = cfirstfreeAttrinbuf; + cfirstfreeAttrinbuf = firstAttr; + tcConnectptr.p->firstAttrinbuf = tcConnectptr.p->lastAttrinbuf = RNIL; + } + } + else + { + jam(); + storedProcConfScanLab(signal); + } +}//Dblqh::accScanConfScanLab() + +#define print_buf(s,idx,len) {\ + printf(s); Uint32 t2=len; DatabufPtr t3; t3.i = idx; \ + while(t3.i != RNIL && t2-- > 0){\ + ptrCheckGuard(t3, cdatabufFileSize, databuf);\ + printf("%d ", t3.i); t3.i= t3.p->nextDatabuf;\ + } printf("\n"); } + +Uint32 +Dblqh::copy_bounds(Uint32 * dst, TcConnectionrec* tcPtrP) +{ + /** + * copy_bounds handles multiple bounds by + * in the 16 upper bits of the first words (used to specify bound type) + * setting the length of this specific bound + * + */ + + DatabufPtr regDatabufptr; + Uint32 left = 4 - tcPtrP->m_offset_current_keybuf; // left in buf + Uint32 totalLen = tcPtrP->primKeyLen - 4; + regDatabufptr.i = tcPtrP->firstTupkeybuf; + + ndbassert(tcPtrP->primKeyLen >= 4); + ndbassert(tcPtrP->m_offset_current_keybuf < 4); + ndbassert(!(totalLen == 0 && regDatabufptr.i != RNIL)); + ndbassert(!(totalLen != 0 && regDatabufptr.i == RNIL)); + + if(totalLen) + { + 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]; + + switch(left){ + case 4: + * dst++ = sig0; + case 3: + * dst++ = sig1; + case 2: + * dst++ = sig2; + case 1: + * dst++ = sig3; + } + + Uint32 first = (* (dst - left)); // First word in range + + // Length of this range + Uint8 offset; + const Uint32 len = (first >> 16) ? (first >> 16) : totalLen; + tcPtrP->m_scan_curr_range_no = (first & 0xFFF0) >> 4; + (* (dst - left)) = (first & 0xF); // Remove length & range no + + if(len < left) + { + offset = len; + } + else + { + Databuf * lastP; + left = (len - left); + regDatabufptr.i = regDatabufptr.p->nextDatabuf; + + while(left >= 4) + { + left -= 4; + lastP = regDatabufptr.p; + ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); + sig0 = regDatabufptr.p->data[0]; + sig1 = regDatabufptr.p->data[1]; + sig2 = regDatabufptr.p->data[2]; + sig3 = regDatabufptr.p->data[3]; + regDatabufptr.i = regDatabufptr.p->nextDatabuf; + + * dst++ = sig0; + * dst++ = sig1; + * dst++ = sig2; + * dst++ = sig3; + } + + if(left > 0) + { + lastP = regDatabufptr.p; + ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf); + sig0 = regDatabufptr.p->data[0]; + sig1 = regDatabufptr.p->data[1]; + sig2 = regDatabufptr.p->data[2]; + sig3 = regDatabufptr.p->data[3]; + * dst++ = sig0; + * dst++ = sig1; + * dst++ = sig2; + * dst++ = sig3; + } + else + { + lastP = regDatabufptr.p; + } + offset = left & 3; + lastP->nextDatabuf = cfirstfreeDatabuf; + cfirstfreeDatabuf = tcPtrP->firstTupkeybuf; + ndbassert(cfirstfreeDatabuf != RNIL); + } + + if(len == totalLen && regDatabufptr.i != RNIL) + { + regDatabufptr.p->nextDatabuf = cfirstfreeDatabuf; + cfirstfreeDatabuf = regDatabufptr.i; + tcPtrP->lastTupkeybuf = regDatabufptr.i = RNIL; + ndbassert(cfirstfreeDatabuf != RNIL); + } + + tcPtrP->m_offset_current_keybuf = offset; + tcPtrP->firstTupkeybuf = regDatabufptr.i; + tcPtrP->primKeyLen = 4 + totalLen - len; + + return len; + } + return totalLen; +} + +/* ------------------------------------------------------------------------- + * 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; + 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->scanLockHold) + { + jam(); + closeScanLab(signal); + return; + } + + if (scanptr.p->scanCompletedStatus == ZTRUE) { + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + jam(); + closeScanLab(signal); + return; + }//if + + if (scanptr.p->m_curr_batch_size_rows > 0) { + jam(); + + if((tcConnectptr.p->primKeyLen - 4) == 0) + scanptr.p->scanCompletedStatus = ZTRUE; + + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + return; + }//if + closeScanLab(signal); + return; + }//if + + // If accOperationPtr == RNIL no record was returned by ACC + if (nextScanConf->accOperationPtr == RNIL) { + jam(); + /************************************************************* + * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. + ************************************************************ */ + if (scanptr.p->scanCompletedStatus == ZTRUE) { + releaseActiveFrag(signal); + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + jam(); + closeScanLab(signal); + return; + }//if + + if (scanptr.p->m_curr_batch_size_rows > 0) { + jam(); + releaseActiveFrag(signal); + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + return; + }//if + + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP; + if (! scanptr.p->rangeScan) + sendSignal(tcConnectptr.p->tcAccBlockref, + GSN_ACC_CHECK_SCAN, signal, 2, JBB); + else + sendSignal(tcConnectptr.p->tcTuxBlockref, + GSN_ACC_CHECK_SCAN, signal, 2, JBB); + return; + }//if + jam(); + set_acc_ptr_in_scan_record(scanptr.p, + scanptr.p->m_curr_batch_size_rows, + nextScanConf->accOperationPtr); + jam(); + scanptr.p->scanLocalref[0] = nextScanConf->localKey[0]; + scanptr.p->scanLocalref[1] = nextScanConf->localKey[1]; + scanptr.p->scanLocalFragid = nextScanConf->fragId; + 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); + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + closeScanLab(signal); + return; + }//if + jam(); + Uint32 tableRef; + Uint32 tupFragPtr; + Uint32 reqinfo = (scanptr.p->scanLockHold == ZFALSE); + reqinfo = reqinfo + (tcConnectptr.p->operation << 6); + reqinfo = reqinfo + (tcConnectptr.p->opExec << 10); + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_TUPKEY; + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (! scanptr.p->rangeScan) { + tableRef = tcConnectptr.p->tableref; + tupFragPtr = fragptr.p->tupFragptr[scanptr.p->scanLocalFragid & 1]; + } else { + jam(); + // for ordered index use primary table + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + tableRef = tFragPtr.p->tabRef; + tupFragPtr = tFragPtr.p->tupFragptr[scanptr.p->scanLocalFragid & 1]; + } + { + jam(); + TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); + + tupKeyReq->connectPtr = tcConnectptr.p->tupConnectrec; + tupKeyReq->request = reqinfo; + tupKeyReq->tableRef = tableRef; + tupKeyReq->fragId = scanptr.p->scanLocalFragid; + tupKeyReq->keyRef1 = scanptr.p->scanLocalref[0]; + tupKeyReq->keyRef2 = scanptr.p->scanLocalref[1]; + tupKeyReq->attrBufLen = 0; + tupKeyReq->opRef = scanptr.p->scanApiOpPtr; + tupKeyReq->applRef = scanptr.p->scanApiBlockref; + tupKeyReq->schemaVersion = scanptr.p->scanSchemaVersion; + tupKeyReq->storedProcedure = scanptr.p->scanStoredProcId; + tupKeyReq->transId1 = tcConnectptr.p->transid[0]; + tupKeyReq->transId2 = tcConnectptr.p->transid[1]; + tupKeyReq->fragPtr = tupFragPtr; + tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; + tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; + tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; + tupKeyReq->savePointId = tcConnectptr.p->savePointId; + Uint32 blockNo = refToBlock(tcConnectptr.p->tcTupBlockref); + EXECUTE_DIRECT(blockNo, GSN_TUPKEYREQ, signal, + TupKeyReq::SignalLength); + } +} + +/* ------------------------------------------------------------------------- + * RECEPTION OF FURTHER KEY INFORMATION WHEN KEY SIZE > 16 BYTES. + * ------------------------------------------------------------------------- + * PRECONDITION: SCAN_STATE = WAIT_SCAN_KEYINFO + * ------------------------------------------------------------------------- */ +void +Dblqh::keyinfoLab(const Uint32 * src, const Uint32 * end) +{ + do { + jam(); + seizeTupkeybuf(0); + databufptr.p->data[0] = * src ++; + databufptr.p->data[1] = * src ++; + databufptr.p->data[2] = * src ++; + databufptr.p->data[3] = * src ++; + } while (src < end); +}//Dblqh::keyinfoLab() + +Uint32 +Dblqh::readPrimaryKeys(ScanRecord *scanP, TcConnectionrec *tcConP, Uint32 *dst) +{ + Uint32 tableId = tcConP->tableref; + Uint32 fragId = scanP->scanLocalFragid; + Uint32 fragPageId = scanP->scanLocalref[0]; + Uint32 pageIndex = scanP->scanLocalref[1]; + + if(scanP->rangeScan) + { + jam(); + // for ordered index use primary table + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + tableId = tFragPtr.p->tabRef; + } + + int ret = c_tup->accReadPk(tableId, fragId, fragPageId, pageIndex, dst, false); + if(0) + ndbout_c("readPrimaryKeys(table: %d fragment: %d [ %d %d ] -> %d", + tableId, fragId, fragPageId, pageIndex, ret); + ndbassert(ret > 0); + + return ret; +} + +/* ------------------------------------------------------------------------- + * ENTER TUPKEYCONF + * ------------------------------------------------------------------------- + * PRECONDITION: TRANSACTION_STATE = SCAN_TUPKEY + * ------------------------------------------------------------------------- */ +void Dblqh::scanTupkeyConfLab(Signal* signal) +{ + const TupKeyConf * conf = (TupKeyConf *)signal->getDataPtr(); + UintR tdata4 = conf->readLength; + UintR tdata5 = conf->lastRow; + + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + scanptr.i = tcConnectptr.p->tcScanRec; + releaseActiveFrag(signal); + c_scanRecordPool.getPtr(scanptr); + if (scanptr.p->scanCompletedStatus == ZTRUE) { + /* --------------------------------------------------------------------- + * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. + * --------------------------------------------------------------------- */ + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + jam(); + closeScanLab(signal); + return; + }//if + if (scanptr.p->scanKeyinfoFlag) { + jam(); + // Inform API about keyinfo len aswell + tdata4 += sendKeyinfo20(signal, scanptr.p, tcConnectptr.p); + }//if + ndbrequire(scanptr.p->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN); + scanptr.p->m_curr_batch_size_bytes+= tdata4; + scanptr.p->m_curr_batch_size_rows++; + scanptr.p->m_last_row = tdata5; + if (scanptr.p->check_scan_batch_completed() | tdata5){ + if (scanptr.p->scanLockHold == ZTRUE) { + jam(); + scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; + sendScanFragConf(signal, ZFALSE); + return; + } else { + jam(); + scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows; + scanReleaseLocksLab(signal); + return; + } + } else { + if (scanptr.p->scanLockHold == ZTRUE) { + jam(); + scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; + } else { + jam(); + scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT; + } + } + scanNextLoopLab(signal); +}//Dblqh::scanTupkeyConfLab() + +void Dblqh::scanNextLoopLab(Signal* signal) +{ + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + }//switch + continueScanAfterBlockedLab(signal); +}//Dblqh::scanNextLoopLab() + +void Dblqh::continueScanAfterBlockedLab(Signal* signal) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + Uint32 accOpPtr; + if (scanptr.p->scanFlag == NextScanReq::ZSCAN_NEXT_ABORT) { + jam(); + scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_COMMIT; + accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, + scanptr.p->m_curr_batch_size_rows, + false); + scanptr.p->scan_acc_index--; + } else if (scanptr.p->scanFlag == NextScanReq::ZSCAN_NEXT_COMMIT) { + jam(); + accOpPtr= get_acc_ptr_from_scan_record(scanptr.p, + scanptr.p->m_curr_batch_size_rows-1, + false); + } else { + jam(); + accOpPtr = RNIL; // The value is not used in ACC + }//if + scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN; + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = accOpPtr; + signal->theData[2] = scanptr.p->scanFlag; + if (! scanptr.p->rangeScan) + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3,JBB); + else + sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3,JBB); +}//Dblqh::continueScanAfterBlockedLab() + +/* ------------------------------------------------------------------------- + * ENTER TUPKEYREF WITH + * TC_CONNECTPTR, + * TERROR_CODE + * ------------------------------------------------------------------------- + * PRECONDITION: TRANSACTION_STATE = SCAN_TUPKEY + * ------------------------------------------------------------------------- */ +void Dblqh::scanTupkeyRefLab(Signal* signal) +{ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + scanptr.i = tcConnectptr.p->tcScanRec; + releaseActiveFrag(signal); + c_scanRecordPool.getPtr(scanptr); + if (scanptr.p->scanCompletedStatus == ZTRUE) { + /* --------------------------------------------------------------------- + * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. + * --------------------------------------------------------------------- */ + if ((scanptr.p->scanLockHold == ZTRUE) && + (scanptr.p->m_curr_batch_size_rows > 0)) { + jam(); + scanptr.p->scanReleaseCounter = 1; + scanReleaseLocksLab(signal); + return; + }//if + jam(); + closeScanLab(signal); + return; + }//if + if ((terrorCode != ZSEARCH_CONDITION_FALSE) && + (terrorCode != ZNO_TUPLE_FOUND) && + (terrorCode >= ZUSER_ERROR_CODE_LIMIT)) { + scanptr.p->scanErrorCounter++; + tcConnectptr.p->errorCode = terrorCode; + + if (scanptr.p->scanLockHold == ZTRUE) { + jam(); + scanptr.p->scanReleaseCounter = 1; + } else { + jam(); + scanptr.p->m_curr_batch_size_rows++; + scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows; + }//if + /* -------------------------------------------------------------------- + * WE NEED TO RELEASE ALL LOCKS CURRENTLY + * HELD BY THIS SCAN. + * -------------------------------------------------------------------- */ + scanReleaseLocksLab(signal); + return; + }//if + Uint32 time_passed= tcConnectptr.p->tcTimer - cLqhTimeOutCount; + if (scanptr.p->m_curr_batch_size_rows > 0) { + if (time_passed > 1) { + /* ----------------------------------------------------------------------- + * WE NEED TO ENSURE THAT WE DO NOT SEARCH FOR THE NEXT TUPLE FOR A + * LONG TIME WHILE WE KEEP A LOCK ON A FOUND TUPLE. WE RATHER REPORT + * THE FOUND TUPLE IF FOUND TUPLES ARE RARE. If more than 10 ms passed we + * send the found tuples to the API. + * ----------------------------------------------------------------------- */ + scanptr.p->scanReleaseCounter = scanptr.p->m_curr_batch_size_rows + 1; + scanReleaseLocksLab(signal); + return; + } + } else { + if (time_passed > 10) { + jam(); + signal->theData[0]= scanptr.i; + signal->theData[1]= tcConnectptr.p->transid[0]; + signal->theData[2]= tcConnectptr.p->transid[1]; + execSCAN_HBREP(signal); + } + } + scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT_ABORT; + scanNextLoopLab(signal); +}//Dblqh::scanTupkeyRefLab() + +/* ------------------------------------------------------------------------- + * THE SCAN HAS BEEN COMPLETED. EITHER BY REACHING THE END OR BY COMMAND + * FROM THE APPLICATION OR BY SOME SORT OF ERROR CONDITION. + * ------------------------------------------------------------------------- */ +void Dblqh::closeScanLab(Signal* signal) +{ + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_CLOSE_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + ndbrequire(false); + }//switch + continueCloseScanAfterBlockedLab(signal); +}//Dblqh::closeScanLab() + +void Dblqh::continueCloseScanAfterBlockedLab(Signal* signal) +{ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanState = ScanRecord::WAIT_CLOSE_SCAN; + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = RNIL; + signal->theData[2] = NextScanReq::ZSCAN_CLOSE; + if (! scanptr.p->rangeScan) + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); + else + sendSignal(tcConnectptr.p->tcTuxBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); +}//Dblqh::continueCloseScanAfterBlockedLab() + +/* ------------------------------------------------------------------------- + * ENTER NEXT_SCANCONF + * ------------------------------------------------------------------------- + * PRECONDITION: SCAN_STATE = WAIT_CLOSE_SCAN + * ------------------------------------------------------------------------- */ +void Dblqh::accScanCloseConfLab(Signal* signal) +{ + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + + if((tcConnectptr.p->primKeyLen - 4) > 0 && + scanptr.p->scanCompletedStatus != ZTRUE) + { + jam(); + releaseActiveFrag(signal); + continueAfterReceivingAllAiLab(signal); + return; + } + + scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN; + 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(); + sendScanFragConf(signal, ZSCAN_FRAG_CLOSED); + }//if + finishScanrec(signal); + releaseScanrec(signal); + tcConnectptr.p->tcScanRec = RNIL; + deleteTransidHash(signal); + releaseOprec(signal); + releaseTcrec(signal, tcConnectptr); +}//Dblqh::tupScanCloseConfLab() + +/* ========================================================================= + * ======= INITIATE SCAN RECORD ======= + * + * SUBROUTINE SHORT NAME = ISC + * ========================================================================= */ +Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) +{ + const Uint32 reqinfo = scanFragReq->requestInfo; + const Uint32 max_rows = scanFragReq->batch_size_rows; + const Uint32 max_bytes = scanFragReq->batch_size_bytes; + const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo); + const Uint32 scanLockHold = ScanFragReq::getHoldLockFlag(reqinfo); + const Uint32 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo); + const Uint32 readCommitted = ScanFragReq::getReadCommittedFlag(reqinfo); + const Uint32 idx = ScanFragReq::getRangeScanFlag(reqinfo); + const Uint32 descending = ScanFragReq::getDescendingFlag(reqinfo); + const Uint32 attrLen = ScanFragReq::getAttrLen(reqinfo); + const Uint32 scanPrio = ScanFragReq::getScanPrio(reqinfo); + + scanptr.p->scanKeyinfoFlag = keyinfo; + scanptr.p->scanLockHold = scanLockHold; + scanptr.p->scanCompletedStatus = ZFALSE; + scanptr.p->scanType = ScanRecord::SCAN; + scanptr.p->scanApiBlockref = scanFragReq->resultRef; + scanptr.p->scanAiLength = attrLen; + scanptr.p->scanTcrec = tcConnectptr.i; + scanptr.p->scanSchemaVersion = scanFragReq->schemaVersion; + + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes= 0; + scanptr.p->m_max_batch_size_rows = max_rows; + scanptr.p->m_max_batch_size_bytes = max_bytes; + + scanptr.p->scanErrorCounter = 0; + scanptr.p->scanLockMode = scanLockMode; + scanptr.p->readCommitted = readCommitted; + scanptr.p->rangeScan = idx; + scanptr.p->descending = descending; + scanptr.p->scanState = ScanRecord::SCAN_FREE; + scanptr.p->scanFlag = ZFALSE; + scanptr.p->scanLocalref[0] = 0; + scanptr.p->scanLocalref[1] = 0; + scanptr.p->scanLocalFragid = 0; + scanptr.p->scanTcWaiting = ZTRUE; + scanptr.p->scanNumber = ~0; + scanptr.p->scanApiOpPtr = scanFragReq->clientOpPtr; + scanptr.p->m_last_row = 0; + scanptr.p->scanStoredProcId = RNIL; + + if (max_rows == 0 || (max_bytes > 0 && max_rows > max_bytes)){ + jam(); + return ScanFragRef::ZWRONG_BATCH_SIZE; + } + if (!seize_acc_ptr_list(scanptr.p, max_rows)){ + jam(); + return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; + } + /** + * Used for scan take over + */ + FragrecordPtr tFragPtr; + tFragPtr.i = fragptr.p->tableFragptr; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + scanptr.p->fragPtrI = fragptr.p->tableFragptr; + + /** + * !idx uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) = 1-11 + * idx uses from MAX_PARALLEL_SCANS_PER_FRAG - MAX = 12-42) + */ + Uint32 start = (idx ? MAX_PARALLEL_SCANS_PER_FRAG : 1 ); + Uint32 stop = (idx ? MAX_PARALLEL_INDEX_SCANS_PER_FRAG : MAX_PARALLEL_SCANS_PER_FRAG - 1); + stop += start; + Uint32 free = tFragPtr.p->m_scanNumberMask.find(start); + + if(free == Fragrecord::ScanNumberMask::NotFound || free >= stop){ + jam(); + + if(scanPrio == 0){ + jam(); + return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; + } + + /** + * Put on queue + */ + scanptr.p->scanState = ScanRecord::IN_QUEUE; + LocalDLFifoList<ScanRecord> queue(c_scanRecordPool, + fragptr.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, fragptr.p->m_activeScans); + active.add(scanptr); + if(scanptr.p->scanKeyinfoFlag){ + jam(); +#ifdef VM_TRACE + ScanRecordPtr tmp; + ndbrequire(!c_scanTakeOverHash.find(tmp, * scanptr.p)); +#endif +#ifdef TRACE_SCAN_TAKEOVER + ndbout_c("adding (%d %d) table: %d fragId: %d frag.i: %d tableFragptr: %d", + scanptr.p->scanNumber, scanptr.p->fragPtrI, + tabptr.i, scanFragReq->fragmentNoKeyLen & 0xFFFF, + fragptr.i, fragptr.p->tableFragptr); +#endif + c_scanTakeOverHash.add(scanptr); + } + init_acc_ptr_list(scanptr.p); + return ZOK; +} + +/* ========================================================================= + * ======= INITIATE TC RECORD AT SCAN ======= + * + * SUBROUTINE SHORT NAME = IST + * ========================================================================= */ +void Dblqh::initScanTc(Signal* signal, + Uint32 transid1, + Uint32 transid2, + Uint32 fragId, + Uint32 nodeId) +{ + tcConnectptr.p->transid[0] = transid1; + tcConnectptr.p->transid[1] = transid2; + tcConnectptr.p->tcScanRec = scanptr.i; + tcConnectptr.p->tableref = tabptr.i; + tcConnectptr.p->fragmentid = fragId; + tcConnectptr.p->fragmentptr = fragptr.i; + tcConnectptr.p->tcOprec = tcConnectptr.p->clientConnectrec; + tcConnectptr.p->tcBlockref = tcConnectptr.p->clientBlockref; + tcConnectptr.p->errorCode = 0; + tcConnectptr.p->reclenAiLqhkey = 0; + tcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; + tcConnectptr.p->nextReplica = nodeId; + tcConnectptr.p->currTupAiLen = 0; + tcConnectptr.p->opExec = 1; + tcConnectptr.p->operation = ZREAD; + tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; + tcConnectptr.p->commitAckMarker = RNIL; + tcConnectptr.p->m_offset_current_keybuf = 0; + tcConnectptr.p->m_scan_curr_range_no = 0; + + tabptr.p->usageCount++; +}//Dblqh::initScanTc() + +/* ========================================================================= + * ======= FINISH SCAN RECORD ======= + * + * REMOVE SCAN RECORD FROM PER FRAGMENT LIST. + * ========================================================================= */ +void Dblqh::finishScanrec(Signal* signal) +{ + release_acc_ptr_list(scanptr.p); + + LocalDLFifoList<ScanRecord> queue(c_scanRecordPool, + fragptr.p->m_queuedScans); + + if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ + jam(); + queue.release(scanptr); + return; + } + + if(scanptr.p->scanKeyinfoFlag){ + jam(); + ScanRecordPtr tmp; +#ifdef TRACE_SCAN_TAKEOVER + ndbout_c("removing (%d %d)", scanptr.p->scanNumber, scanptr.p->fragPtrI); +#endif + c_scanTakeOverHash.remove(tmp, * scanptr.p); + ndbrequire(tmp.p == scanptr.p); + } + + LocalDLList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans); + scans.release(scanptr); + + FragrecordPtr tFragPtr; + tFragPtr.i = scanptr.p->fragPtrI; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + + 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; + } + + ndbrequire(restart.p->scanState == ScanRecord::IN_QUEUE); + + ScanRecordPtr tmpScan = scanptr; + TcConnectionrecPtr tmpTc = tcConnectptr; + + tcConnectptr.i = restart.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + restart.p->scanNumber = scanNumber; + + queue.remove(restart); + scans.add(restart); + if(restart.p->scanKeyinfoFlag){ + jam(); +#ifdef VM_TRACE + ScanRecordPtr tmp; + ndbrequire(!c_scanTakeOverHash.find(tmp, * restart.p)); +#endif + c_scanTakeOverHash.add(restart); +#ifdef TRACE_SCAN_TAKEOVER + ndbout_c("adding-r (%d %d)", restart.p->scanNumber, restart.p->fragPtrI); +#endif + } + + restart.p->scanState = ScanRecord::SCAN_FREE; // set in initScanRec + if(tcConnectptr.p->transactionState == TcConnectionrec::SCAN_STATE_USED) + { + jam(); + scanptr = restart; + continueAfterReceivingAllAiLab(signal); + } + else + { + ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::WAIT_SCAN_AI); + } + scanptr = tmpScan; + tcConnectptr = tmpTc; +}//Dblqh::finishScanrec() + +/* ========================================================================= + * ======= RELEASE SCAN RECORD ======= + * + * RELEASE A SCAN RECORD TO THE FREELIST. + * ========================================================================= */ +void Dblqh::releaseScanrec(Signal* signal) +{ + scanptr.p->scanState = ScanRecord::SCAN_FREE; + scanptr.p->scanType = ScanRecord::ST_IDLE; + scanptr.p->scanTcWaiting = ZFALSE; + cbookedAccOps -= scanptr.p->m_max_batch_size_rows; + cscanNoFreeRec++; +}//Dblqh::releaseScanrec() + +/* ------------------------------------------------------------------------ + * ------- SEND KEYINFO20 TO API ------- + * + * ------------------------------------------------------------------------ */ +Uint32 Dblqh::sendKeyinfo20(Signal* signal, + ScanRecord * scanP, + TcConnectionrec * tcConP) +{ + ndbrequire(scanP->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN); + KeyInfo20 * keyInfo = (KeyInfo20 *)&signal->theData[0]; + + /** + * Note that this code requires signal->theData to be big enough for + * a entire key + */ + const BlockReference ref = scanP->scanApiBlockref; + const Uint32 scanOp = scanP->m_curr_batch_size_rows; + const Uint32 nodeId = refToNode(ref); + const bool connectedToNode = getNodeInfo(nodeId).m_connected; + const Uint32 type = getNodeInfo(nodeId).m_type; + const bool is_api = (type >= NodeInfo::API && type <= NodeInfo::REP); + const bool old_dest = (getNodeInfo(nodeId).m_version < MAKE_VERSION(3,5,0)); + const bool longable = true; // TODO is_api && !old_dest; + + Uint32 * dst = keyInfo->keyData; + dst += nodeId == getOwnNodeId() ? 0 : KeyInfo20::DataLength; + + Uint32 keyLen = readPrimaryKeys(scanP, tcConP, dst); + Uint32 fragId = tcConP->fragmentid; + keyInfo->clientOpPtr = scanP->scanApiOpPtr; + keyInfo->keyLen = keyLen; + keyInfo->scanInfo_Node = + KeyInfo20::setScanInfo(scanOp, scanP->scanNumber) + (fragId << 20); + keyInfo->transId1 = tcConP->transid[0]; + keyInfo->transId2 = tcConP->transid[1]; + + Uint32 * src = signal->theData+25; + if(connectedToNode){ + jam(); + + if(nodeId != getOwnNodeId()){ + jam(); + + if(keyLen <= KeyInfo20::DataLength || !longable) { + while(keyLen > KeyInfo20::DataLength){ + jam(); + MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength); + sendSignal(ref, GSN_KEYINFO20, signal, 25, JBB); + src += KeyInfo20::DataLength;; + keyLen -= KeyInfo20::DataLength; + } + + MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen); + sendSignal(ref, GSN_KEYINFO20, signal, + KeyInfo20::HeaderLength+keyLen, JBB); + return keyLen; + } + + LinearSectionPtr ptr[3]; + ptr[0].p = src; + ptr[0].sz = keyLen; + sendSignal(ref, GSN_KEYINFO20, signal, KeyInfo20::HeaderLength, + JBB, ptr, 1); + return keyLen; + } + + EXECUTE_DIRECT(refToBlock(ref), GSN_KEYINFO20, signal, + KeyInfo20::HeaderLength + keyLen); + jamEntry(); + return keyLen; + } + + /** + * If this node does not have a direct connection + * to the receiving node we want to send the signals + * routed via the node that controls this read + */ + Uint32 routeBlockref = tcConP->clientBlockref; + + if(keyLen < KeyInfo20::DataLength || !longable){ + jam(); + + while (keyLen > (KeyInfo20::DataLength - 1)) { + jam(); + MEMCOPY_NO_WORDS(keyInfo->keyData, src, KeyInfo20::DataLength - 1); + keyInfo->keyData[KeyInfo20::DataLength-1] = ref; + sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, 25, JBB); + src += KeyInfo20::DataLength - 1; + keyLen -= KeyInfo20::DataLength - 1; + } + + MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen); + keyInfo->keyData[keyLen] = ref; + sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, + KeyInfo20::HeaderLength+keyLen+1, JBB); + return keyLen; + } + + keyInfo->keyData[0] = ref; + LinearSectionPtr ptr[3]; + ptr[0].p = src; + ptr[0].sz = keyLen; + sendSignal(routeBlockref, GSN_KEYINFO20_R, signal, + KeyInfo20::HeaderLength+1, JBB, ptr, 1); + return keyLen; +} + +/* ------------------------------------------------------------------------ + * ------- SEND SCAN_FRAGCONF TO TC THAT CONTROLS THE SCAN ------- + * + * ------------------------------------------------------------------------ */ +void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) +{ + Uint32 completed_ops= scanptr.p->m_curr_batch_size_rows; + Uint32 total_len= scanptr.p->m_curr_batch_size_bytes; + scanptr.p->scanTcWaiting = ZFALSE; + + if(ERROR_INSERTED(5037)){ + CLEAR_ERROR_INSERT_VALUE; + return; + } + ScanFragConf * conf = (ScanFragConf*)&signal->theData[0]; + NodeId tc_node_id= refToNode(tcConnectptr.p->clientBlockref); + Uint32 trans_id1= tcConnectptr.p->transid[0]; + Uint32 trans_id2= tcConnectptr.p->transid[1]; + + conf->senderData = tcConnectptr.p->clientConnectrec; + conf->completedOps = completed_ops; + conf->fragmentCompleted = scanCompleted; + conf->transId1 = trans_id1; + conf->transId2 = trans_id2; + conf->total_len= total_len; + sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGCONF, + signal, ScanFragConf::SignalLength, JBB); + + if(!scanptr.p->scanLockHold) + { + jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes= 0; + } +}//Dblqh::sendScanFragConf() + +/* ######################################################################### */ +/* ####### NODE RECOVERY MODULE ####### */ +/* */ +/* ######################################################################### */ +/*---------------------------------------------------------------------------*/ +/* */ +/* THIS MODULE IS USED WHEN A NODE HAS FAILED. IT PERFORMS A COPY OF A */ +/* FRAGMENT TO A NEW REPLICA OF THE FRAGMENT. IT DOES ALSO SHUT DOWN ALL */ +/* CONNECTIONS TO THE FAILED NODE. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::calculateHash(Signal* signal) +{ + DatabufPtr locDatabufptr; + UintR Ti; + UintR Tdata0; + UintR Tdata1; + UintR Tdata2; + UintR Tdata3; + UintR* Tdata32; + Uint64 Tdata[512]; + + Tdata32 = (UintR*)&Tdata[0]; + + Tdata0 = tcConnectptr.p->tupkeyData[0]; + Tdata1 = tcConnectptr.p->tupkeyData[1]; + Tdata2 = tcConnectptr.p->tupkeyData[2]; + Tdata3 = tcConnectptr.p->tupkeyData[3]; + Tdata32[0] = Tdata0; + Tdata32[1] = Tdata1; + Tdata32[2] = Tdata2; + Tdata32[3] = Tdata3; + locDatabufptr.i = tcConnectptr.p->firstTupkeybuf; + Ti = 4; + while (locDatabufptr.i != RNIL) { + ptrCheckGuard(locDatabufptr, cdatabufFileSize, databuf); + Tdata0 = locDatabufptr.p->data[0]; + Tdata1 = locDatabufptr.p->data[1]; + Tdata2 = locDatabufptr.p->data[2]; + Tdata3 = locDatabufptr.p->data[3]; + Tdata32[Ti ] = Tdata0; + Tdata32[Ti + 1] = Tdata1; + Tdata32[Ti + 2] = Tdata2; + Tdata32[Ti + 3] = Tdata3; + locDatabufptr.i = locDatabufptr.p->nextDatabuf; + Ti += 4; + }//while + tcConnectptr.p->hashValue = + md5_hash((Uint64*)&Tdata32[0], (UintR)tcConnectptr.p->primKeyLen); +}//Dblqh::calculateHash() + +/* *************************************** */ +/* COPY_FRAGREQ: Start copying a fragment */ +/* *************************************** */ +void Dblqh::execCOPY_FRAGREQ(Signal* signal) +{ + jamEntry(); + const CopyFragReq * const copyFragReq = (CopyFragReq *)&signal->theData[0]; + tabptr.i = copyFragReq->tableId; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + const Uint32 fragId = copyFragReq->fragId; + const Uint32 copyPtr = copyFragReq->userPtr; + const Uint32 userRef = copyFragReq->userRef; + const Uint32 nodeId = copyFragReq->nodeId; + + ndbrequire(cnoActiveCopy < 3); + ndbrequire(getFragmentrec(signal, fragId)); + ndbrequire(fragptr.p->copyFragState == ZIDLE); + ndbrequire(cfirstfreeTcConrec != RNIL); + ndbrequire(fragptr.p->m_scanNumberMask.get(NR_ScanNo)); + + fragptr.p->fragDistributionKey = copyFragReq->distributionKey; + + if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) { + jam(); + /** + * Ordered index doesn't need to be copied + */ + CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0]; + conf->userPtr = copyPtr; + conf->sendingNodeId = cownNodeid; + conf->startingNodeId = nodeId; + conf->tableId = tabptr.i; + conf->fragId = fragId; + sendSignal(userRef, GSN_COPY_FRAGCONF, signal, + CopyFragConf::SignalLength, JBB); + return; + }//if + + LocalDLList<ScanRecord> scans(c_scanRecordPool, fragptr.p->m_activeScans); + ndbrequire(scans.seize(scanptr)); +/* ------------------------------------------------------------------------- */ +// We keep track of how many operation records in ACC that has been booked. +// Copy fragment has records always booked and thus need not book any. The +// most operations in parallel use is the m_max_batch_size_rows. +// This variable has to be set-up here since it is used by releaseScanrec +// to unbook operation records in ACC. +/* ------------------------------------------------------------------------- */ + scanptr.p->m_max_batch_size_rows = 0; + scanptr.p->rangeScan = 0; + seizeTcrec(); + + /** + * Remove implicit cast/usage of CopyFragReq + */ + //initCopyrec(signal); + scanptr.p->copyPtr = copyPtr; + scanptr.p->scanType = ScanRecord::COPY; + scanptr.p->scanApiBlockref = userRef; + scanptr.p->scanNodeId = nodeId; + scanptr.p->scanTcrec = tcConnectptr.i; + scanptr.p->scanSchemaVersion = copyFragReq->schemaVersion; + scanptr.p->scanCompletedStatus = ZFALSE; + scanptr.p->scanErrorCounter = 0; + scanptr.p->scanNumber = NR_ScanNo; + scanptr.p->scanKeyinfoFlag = 0; // Don't put into hash + scanptr.p->fragPtrI = fragptr.i; + fragptr.p->m_scanNumberMask.clear(NR_ScanNo); + + initScanTc(signal, + 0, + (DBLQH << 20) + (cownNodeid << 8), + fragId, + copyFragReq->nodeId); + cactiveCopy[cnoActiveCopy] = fragptr.i; + cnoActiveCopy++; + + tcConnectptr.p->copyCountWords = 0; + tcConnectptr.p->tcOprec = tcConnectptr.i; + tcConnectptr.p->schemaVersion = scanptr.p->scanSchemaVersion; + scanptr.p->scanState = ScanRecord::WAIT_ACC_COPY; + AccScanReq * req = (AccScanReq*)&signal->theData[0]; + req->senderData = scanptr.i; + req->senderRef = cownref; + req->tableId = tabptr.i; + req->fragmentNo = fragId; + req->requestInfo = 0; + AccScanReq::setLockMode(req->requestInfo, 0); + AccScanReq::setReadCommittedFlag(req->requestInfo, 0); + req->transId1 = tcConnectptr.p->transid[0]; + req->transId2 = tcConnectptr.p->transid[1]; + req->savePointId = tcConnectptr.p->savePointId; + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_SCANREQ, signal, + AccScanReq::SignalLength, JBB); + return; +}//Dblqh::execCOPY_FRAGREQ() + +void Dblqh::accScanConfCopyLab(Signal* signal) +{ + AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0]; + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); +/*--------------------------------------------------------------------------*/ +/* PRECONDITION: SCAN_STATE = WAIT_ACC_COPY */ +/*--------------------------------------------------------------------------*/ + if (accScanConf->flag == AccScanConf::ZEMPTY_FRAGMENT) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE FRAGMENT WAS EMPTY. */ +/* REPORT SUCCESSFUL COPYING. */ +/*---------------------------------------------------------------------------*/ + tupCopyCloseConfLab(signal); + return; + }//if + scanptr.p->scanAccPtr = accScanConf->accPtr; + scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_COPY; + signal->theData[0] = tcConnectptr.p->tupConnectrec; + signal->theData[1] = tcConnectptr.p->tableref; + signal->theData[2] = scanptr.p->scanSchemaVersion; + signal->theData[3] = ZSTORED_PROC_COPY; +// theData[4] is not used in TUP with ZSTORED_PROC_COPY + sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); + return; +}//Dblqh::accScanConfCopyLab() + +/*---------------------------------------------------------------------------*/ +/* ENTER STORED_PROCCONF WITH */ +/* TC_CONNECTPTR, */ +/* TSTORED_PROC_ID */ +/*---------------------------------------------------------------------------*/ +void Dblqh::storedProcConfCopyLab(Signal* signal) +{ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: SCAN_STATE = WAIT_STORED_PROC_COPY */ +/*---------------------------------------------------------------------------*/ + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (scanptr.p->scanCompletedStatus == ZTRUE) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE COPY PROCESS HAVE BEEN COMPLETED, MOST LIKELY DUE TO A NODE FAILURE.*/ +/*---------------------------------------------------------------------------*/ + closeCopyLab(signal); + return; + }//if + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY; + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::COPY_FIRST_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + continueFirstCopyAfterBlockedLab(signal); + return; +}//Dblqh::storedProcConfCopyLab() + +void Dblqh::continueFirstCopyAfterBlockedLab(Signal* signal) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = RNIL; + signal->theData[2] = NextScanReq::ZSCAN_NEXT; + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); + return; +}//Dblqh::continueFirstCopyAfterBlockedLab() + +/*---------------------------------------------------------------------------*/ +/* ENTER NEXT_SCANCONF WITH */ +/* SCANPTR, */ +/* TFRAGID, */ +/* TACC_OPPTR, */ +/* TLOCAL_KEY1, */ +/* TLOCAL_KEY2, */ +/* TKEY_LENGTH, */ +/* TKEY1, */ +/* TKEY2, */ +/* TKEY3, */ +/* TKEY4 */ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: SCAN_STATE = WAIT_NEXT_SCAN_COPY */ +/*---------------------------------------------------------------------------*/ +void Dblqh::nextScanConfCopyLab(Signal* signal) +{ + NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0]; + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + if (nextScanConf->fragId == RNIL) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THERE ARE NO MORE TUPLES TO FETCH. WE NEED TO CLOSE */ +/* THE COPY IN ACC AND DELETE THE STORED PROCEDURE IN TUP */ +/*---------------------------------------------------------------------------*/ + releaseActiveFrag(signal); + if (tcConnectptr.p->copyCountWords == 0) { + closeCopyLab(signal); + return; + }//if +/*---------------------------------------------------------------------------*/ +// Wait until copying is completed also at the starting node before reporting +// completion. Signal completion through scanCompletedStatus-flag. +/*---------------------------------------------------------------------------*/ + scanptr.p->scanCompletedStatus = ZTRUE; + return; + }//if + + // If accOperationPtr == RNIL no record was returned by ACC + if (nextScanConf->accOperationPtr == RNIL) { + jam(); + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP; + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB); + return; + } + + set_acc_ptr_in_scan_record(scanptr.p, 0, nextScanConf->accOperationPtr); + initCopyTc(signal); + 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); + tupFragPtr = fragptr.p->tupFragptr[scanptr.p->scanLocalFragid & 1]; + { + TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend(); + + tupKeyReq->connectPtr = tcConnectptr.p->tupConnectrec; + tupKeyReq->request = reqinfo; + tupKeyReq->tableRef = tcConnectptr.p->tableref; + tupKeyReq->fragId = scanptr.p->scanLocalFragid; + tupKeyReq->keyRef1 = scanptr.p->scanLocalref[0]; + tupKeyReq->keyRef2 = scanptr.p->scanLocalref[1]; + tupKeyReq->attrBufLen = 0; + tupKeyReq->opRef = tcConnectptr.i; + tupKeyReq->applRef = cownref; + tupKeyReq->schemaVersion = scanptr.p->scanSchemaVersion; + tupKeyReq->storedProcedure = scanptr.p->scanStoredProcId; + tupKeyReq->transId1 = tcConnectptr.p->transid[0]; + tupKeyReq->transId2 = tcConnectptr.p->transid[1]; + tupKeyReq->fragPtr = tupFragPtr; + tupKeyReq->primaryReplica = (tcConnectptr.p->seqNoReplica == 0)?true:false; + tupKeyReq->coordinatorTC = tcConnectptr.p->tcBlockref; + tupKeyReq->tcOpIndex = tcConnectptr.p->tcOprec; + tupKeyReq->savePointId = tcConnectptr.p->savePointId; + Uint32 blockNo = refToBlock(tcConnectptr.p->tcTupBlockref); + EXECUTE_DIRECT(blockNo, GSN_TUPKEYREQ, signal, + TupKeyReq::SignalLength); + } +}//Dblqh::copySendTupkeyReqLab() + +/*---------------------------------------------------------------------------*/ +/* USED IN COPYING OPERATION TO RECEIVE ATTRINFO FROM TUP. */ +/*---------------------------------------------------------------------------*/ +/* ************>> */ +/* TRANSID_AI > */ +/* ************>> */ +void Dblqh::execTRANSID_AI(Signal* signal) +{ + jamEntry(); + tcConnectptr.i = signal->theData[0]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + Uint32 length = signal->length() - 3; + ndbrequire(tcConnectptr.p->transactionState == TcConnectionrec::COPY_TUPKEY); + Uint32 * src = &signal->theData[3]; + while(length > 22){ + if (saveTupattrbuf(signal, src, 22) == ZOK) { + ; + } else { + jam(); + tcConnectptr.p->errorCode = ZGET_ATTRINBUF_ERROR; + return; + }//if + src += 22; + length -= 22; + } + if (saveTupattrbuf(signal, src, length) == ZOK) { + return; + } + jam(); + tcConnectptr.p->errorCode = ZGET_ATTRINBUF_ERROR; +}//Dblqh::execTRANSID_AI() + +/*--------------------------------------------------------------------------*/ +/* ENTER TUPKEYCONF WITH */ +/* TC_CONNECTPTR, */ +/* TDATA2, */ +/* TDATA3, */ +/* TDATA4, */ +/* TDATA5 */ +/*--------------------------------------------------------------------------*/ +/* PRECONDITION: TRANSACTION_STATE = COPY_TUPKEY */ +/*--------------------------------------------------------------------------*/ +void Dblqh::copyTupkeyConfLab(Signal* signal) +{ + const TupKeyConf * const tupKeyConf = (TupKeyConf *)signal->getDataPtr(); + + UintR readLength = tupKeyConf->readLength; + + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + ScanRecord* scanP = scanptr.p; + 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 + TcConnectionrec * tcConP = tcConnectptr.p; + tcConnectptr.p->totSendlenAi = readLength; + tcConnectptr.p->connectState = TcConnectionrec::COPY_CONNECTED; + + // Read primary keys (used to get here via scan keyinfo) + Uint32* tmp = signal->getDataPtrSend()+24; + Uint32 len= tcConnectptr.p->primKeyLen = readPrimaryKeys(scanP, tcConP, tmp); + + // Calculate hash (no need to linearies key) + tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len); + + // Move into databuffer to make packLqhkeyreqLab happy + memcpy(tcConP->tupkeyData, tmp, 4*4); + if(len > 4) + keyinfoLab(tmp+4, tmp + len); + LqhKeyReq::setKeyLen(tcConP->reqinfo, len); + +/*---------------------------------------------------------------------------*/ +// 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 + len; + TnoOfWords = TnoOfWords + MAGIC_CONSTANT; + TnoOfWords = TnoOfWords + (TnoOfWords >> 2); + + /*----------------------------------------------------------------- + * NOTE for transid1! + * Transid1 in the tcConnection record is used load regulate the + * copy(node recovery) process. + * The number of outstanding words are written in the transid1 + * variable. This will be sent to the starting node in the + * LQHKEYREQ signal and when the answer is returned in the LQHKEYCONF + * we can reduce the number of outstanding words and check to see + * if more LQHKEYREQ signals should be sent. + * + * However efficient this method is rather unsafe in such way that + * it overwrites the transid1 original data. + * + * Also see TR 587. + *----------------------------------------------------------------*/ + tcConnectptr.p->transid[0] = TnoOfWords; // Data overload, see note! + packLqhkeyreqLab(signal); + tcConnectptr.p->copyCountWords += TnoOfWords; + scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY; + if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) { + nextRecordCopy(signal); + return; + }//if + return; +}//Dblqh::copyTupkeyConfLab() + +/*---------------------------------------------------------------------------*/ +/* ENTER LQHKEYCONF */ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: CONNECT_STATE = COPY_CONNECTED */ +/*---------------------------------------------------------------------------*/ +void Dblqh::copyCompletedLab(Signal* signal) +{ + const LqhKeyConf * const lqhKeyConf = (LqhKeyConf *)signal->getDataPtr(); + + ndbrequire(tcConnectptr.p->transid[1] == lqhKeyConf->transId2); + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + if (tcConnectptr.p->copyCountWords >= cmaxWordsAtNodeRec) { + tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note! + if (scanptr.p->scanCompletedStatus == ZTRUE) { + jam(); +/*---------------------------------------------------------------------------*/ +// Copy to complete, we will not start any new copying. +/*---------------------------------------------------------------------------*/ + closeCopyLab(signal); + return; + }//if + if (tcConnectptr.p->copyCountWords < cmaxWordsAtNodeRec) { + jam(); + nextRecordCopy(signal); + }//if + return; + }//if + tcConnectptr.p->copyCountWords -= lqhKeyConf->transId1; // Data overload, see note! + ndbrequire(tcConnectptr.p->copyCountWords <= cmaxWordsAtNodeRec); + if (tcConnectptr.p->copyCountWords > 0) { + jam(); + return; + }//if +/*---------------------------------------------------------------------------*/ +// No more outstanding copies. We will only start new ones from here if it was +// stopped before and this only happens when copyCountWords is bigger than the +// threshold value. Since this did not occur we must be waiting for completion. +// Check that this is so. If not we crash to find out what is going on. +/*---------------------------------------------------------------------------*/ + if (scanptr.p->scanCompletedStatus == ZTRUE) { + jam(); + closeCopyLab(signal); + return; + }//if + if (scanptr.p->scanState == ScanRecord::WAIT_LQHKEY_COPY) { + jam(); +/*---------------------------------------------------------------------------*/ +// Make sure that something is in progress. Otherwise we will simply stop +// and nothing more will happen. +/*---------------------------------------------------------------------------*/ + systemErrorLab(signal); + return; + }//if + return; +}//Dblqh::copyCompletedLab() + +void Dblqh::nextRecordCopy(Signal* signal) +{ + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + if (scanptr.p->scanState != ScanRecord::WAIT_LQHKEY_COPY) { + jam(); +/*---------------------------------------------------------------------------*/ +// Make sure that nothing is in progress. Otherwise we will have to simultaneous +// scans on the same record and this will certainly lead to unexpected +// behaviour. +/*---------------------------------------------------------------------------*/ + systemErrorLab(signal); + return; + }//if + scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN_COPY; + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::COPY_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + continueCopyAfterBlockedLab(signal); + return; +}//Dblqh::nextRecordCopy() + +void Dblqh::continueCopyAfterBlockedLab(Signal* signal) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + tcConnectptr.p->errorCode = 0; + Uint32 acc_op_ptr= get_acc_ptr_from_scan_record(scanptr.p, 0, false); + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = acc_op_ptr; + signal->theData[2] = NextScanReq::ZSCAN_NEXT_COMMIT; + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); + return; +}//Dblqh::continueCopyAfterBlockedLab() + +void Dblqh::copyLqhKeyRefLab(Signal* signal) +{ + ndbrequire(tcConnectptr.p->transid[1] == signal->theData[4]); + tcConnectptr.p->copyCountWords -= signal->theData[3]; + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanErrorCounter++; + tcConnectptr.p->errorCode = terrorCode; + closeCopyLab(signal); + return; +}//Dblqh::copyLqhKeyRefLab() + +void Dblqh::closeCopyLab(Signal* signal) +{ + if (tcConnectptr.p->copyCountWords > 0) { +/*---------------------------------------------------------------------------*/ +// We are still waiting for responses from the starting node. +// Wait until all of those have arrived until we start the +// close process. +/*---------------------------------------------------------------------------*/ + jam(); + return; + }//if + tcConnectptr.p->transid[0] = 0; + tcConnectptr.p->transid[1] = 0; + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + scanptr.p->scanState = ScanRecord::WAIT_CLOSE_COPY; + switch (fragptr.p->fragStatus) { + case Fragrecord::FSACTIVE: + jam(); + linkActiveFrag(signal); + break; + case Fragrecord::BLOCKED: + jam(); + linkFragQueue(signal); + tcConnectptr.p->transactionState = TcConnectionrec::COPY_CLOSE_STOPPED; + return; + break; + case Fragrecord::FREE: + jam(); + case Fragrecord::ACTIVE_CREATION: + jam(); + case Fragrecord::CRASH_RECOVERING: + jam(); + case Fragrecord::DEFINED: + jam(); + case Fragrecord::REMOVING: + jam(); + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + continueCloseCopyAfterBlockedLab(signal); + return; +}//Dblqh::closeCopyLab() + +void Dblqh::continueCloseCopyAfterBlockedLab(Signal* signal) +{ + scanptr.i = tcConnectptr.p->tcScanRec; + c_scanRecordPool.getPtr(scanptr); + signal->theData[0] = scanptr.p->scanAccPtr; + signal->theData[1] = RNIL; + signal->theData[2] = ZCOPY_CLOSE; + sendSignal(tcConnectptr.p->tcAccBlockref, GSN_NEXT_SCANREQ, signal, 3, JBB); + return; +}//Dblqh::continueCloseCopyAfterBlockedLab() + +/*---------------------------------------------------------------------------*/ +/* ENTER NEXT_SCANCONF WITH */ +/* SCANPTR, */ +/* TFRAGID, */ +/* TACC_OPPTR, */ +/* TLOCAL_KEY1, */ +/* TLOCAL_KEY2, */ +/* TKEY_LENGTH, */ +/* TKEY1, */ +/* TKEY2, */ +/* TKEY3, */ +/* TKEY4 */ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: SCAN_STATE = WAIT_CLOSE_COPY */ +/*---------------------------------------------------------------------------*/ +void Dblqh::accCopyCloseConfLab(Signal* signal) +{ + tcConnectptr.i = scanptr.p->scanTcrec; + scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_COPY; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + signal->theData[0] = tcConnectptr.p->tupConnectrec; + signal->theData[1] = tcConnectptr.p->tableref; + signal->theData[2] = scanptr.p->scanSchemaVersion; + signal->theData[3] = ZDELETE_STORED_PROC_ID; + signal->theData[4] = scanptr.p->scanStoredProcId; + sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); + return; +}//Dblqh::accCopyCloseConfLab() + +/*---------------------------------------------------------------------------*/ +/* ENTER STORED_PROCCONF WITH */ +/* TC_CONNECTPTR, */ +/* TSTORED_PROC_ID */ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: SCAN_STATE = WAIT_DELETE_STORED_PROC_ID_COPY */ +/*---------------------------------------------------------------------------*/ +void Dblqh::tupCopyCloseConfLab(Signal* signal) +{ + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->copyFragState = ZIDLE; + + if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) { + jam(); + tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; + ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); + tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; + signal->theData[0] = ZLQH_TRANS_NEXT; + signal->theData[1] = tcNodeFailptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + + CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0]; + ref->userPtr = scanptr.p->copyPtr; + ref->sendingNodeId = cownNodeid; + ref->startingNodeId = scanptr.p->scanNodeId; + ref->tableId = fragptr.p->tabRef; + ref->fragId = fragptr.p->fragId; + ref->errorCode = ZNODE_FAILURE_ERROR; + sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGREF, signal, + CopyFragRef::SignalLength, JBB); + } else { + if (scanptr.p->scanErrorCounter > 0) { + jam(); + CopyFragRef * const ref = (CopyFragRef *)&signal->theData[0]; + ref->userPtr = scanptr.p->copyPtr; + ref->sendingNodeId = cownNodeid; + ref->startingNodeId = scanptr.p->scanNodeId; + ref->tableId = fragptr.p->tabRef; + ref->fragId = fragptr.p->fragId; + ref->errorCode = tcConnectptr.p->errorCode; + sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGREF, signal, + CopyFragRef::SignalLength, JBB); + } else { + jam(); + CopyFragConf * const conf = (CopyFragConf *)&signal->theData[0]; + conf->userPtr = scanptr.p->copyPtr; + conf->sendingNodeId = cownNodeid; + conf->startingNodeId = scanptr.p->scanNodeId; + conf->tableId = tcConnectptr.p->tableref; + conf->fragId = tcConnectptr.p->fragmentid; + sendSignal(scanptr.p->scanApiBlockref, GSN_COPY_FRAGCONF, signal, + CopyFragConf::SignalLength, JBB); + }//if + }//if + releaseActiveCopy(signal); + tcConnectptr.p->tcScanRec = RNIL; + finishScanrec(signal); + releaseOprec(signal); + releaseTcrec(signal, tcConnectptr); + releaseScanrec(signal); +}//Dblqh::tupCopyCloseConfLab() + +/*---------------------------------------------------------------------------*/ +/* A NODE FAILURE OCCURRED DURING THE COPY PROCESS. WE NEED TO CLOSE THE */ +/* COPY PROCESS SINCE A NODE FAILURE DURING THE COPY PROCESS WILL ALSO */ +/* FAIL THE NODE THAT IS TRYING TO START-UP. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::closeCopyRequestLab(Signal* signal) +{ + scanptr.p->scanErrorCounter++; + switch (scanptr.p->scanState) { + case ScanRecord::WAIT_TUPKEY_COPY: + case ScanRecord::WAIT_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]; + 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::setLockType(reqinfo, ZINSERT); + LqhKeyReq::setDirtyFlag(reqinfo, 1); + LqhKeyReq::setSimpleFlag(reqinfo, 1); + LqhKeyReq::setOperation(reqinfo, ZWRITE); + /* AILen in LQHKEYREQ IS ZERO */ + tcConnectptr.p->reqinfo = reqinfo; +/* ------------------------------------------------------------------------ */ +/* THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL */ +/* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET. */ +/* ------------------------------------------------------------------------ */ + tcConnectptr.p->nodeAfterNext[0] = ZNIL; + tcConnectptr.p->nodeAfterNext[1] = ZNIL; + tcConnectptr.p->tcBlockref = cownref; + tcConnectptr.p->readlenAi = 0; + tcConnectptr.p->storedProcId = ZNIL; + tcConnectptr.p->opExec = 0; + tcConnectptr.p->nextSeqNoReplica = 0; + tcConnectptr.p->dirtyOp = ZFALSE; + tcConnectptr.p->lastReplicaNo = 0; + tcConnectptr.p->currTupAiLen = 0; + tcConnectptr.p->tcTimer = cLqhTimeOutCount; +}//Dblqh::initCopyTc() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND COPY_ACTIVECONF TO MASTER DIH ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::sendCopyActiveConf(Signal* signal, Uint32 tableId) +{ + releaseActiveCopy(signal); + CopyActiveConf * const conf = (CopyActiveConf *)&signal->theData[0]; + conf->userPtr = fragptr.p->masterPtr; + conf->tableId = tableId; + conf->fragId = fragptr.p->fragId; + conf->startingNodeId = cownNodeid; + conf->startGci = fragptr.p->startGci; + sendSignal(fragptr.p->masterBlockref, GSN_COPY_ACTIVECONF, signal, + CopyActiveConf::SignalLength, JBB); +}//Dblqh::sendCopyActiveConf() + +/* ########################################################################## + * ####### LOCAL CHECKPOINT MODULE ####### + * + * ########################################################################## + * -------------------------------------------------------------------------- + * THIS MODULE HANDLES THE EXECUTION AND CONTROL OF LOCAL CHECKPOINTS + * IT CONTROLS THE LOCAL CHECKPOINTS IN TUP AND ACC. IT DOES ALSO INTERACT + * WITH DIH TO CONTROL WHICH GLOBAL CHECKPOINTS THAT ARE RECOVERABLE + * ------------------------------------------------------------------------- */ +void Dblqh::execEMPTY_LCP_REQ(Signal* signal) +{ + jamEntry(); + CRASH_INSERTION(5008); + EmptyLcpReq * const emptyLcpOrd = (EmptyLcpReq*)&signal->theData[0]; + + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + + Uint32 nodeId = refToNode(emptyLcpOrd->senderRef); + + lcpPtr.p->m_EMPTY_LCP_REQ.set(nodeId); + lcpPtr.p->reportEmpty = true; + + if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE){ + jam(); + bool ok = false; + switch(clcpCompletedState){ + case LCP_IDLE: + ok = true; + sendEMPTY_LCP_CONF(signal, true); + break; + case LCP_RUNNING: + ok = true; + sendEMPTY_LCP_CONF(signal, false); + break; + case LCP_CLOSE_STARTED: + jam(); + case ACC_LCP_CLOSE_COMPLETED: + jam(); + case TUP_LCP_CLOSE_COMPLETED: + jam(); + ok = true; + break; + } + ndbrequire(ok); + + }//if + + return; +}//Dblqh::execEMPTY_LCPREQ() + +void Dblqh::execLCP_FRAG_ORD(Signal* signal) +{ + jamEntry(); + CRASH_INSERTION(5010); + LcpFragOrd * const lcpFragOrd = (LcpFragOrd *)&signal->theData[0]; + Uint32 lcpId = lcpFragOrd->lcpId; + + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + + lcpPtr.p->lastFragmentFlag = lcpFragOrd->lastFragmentFlag; + if (lcpFragOrd->lastFragmentFlag) { + jam(); + if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { + jam(); + /* ---------------------------------------------------------- + * NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED. + * -------------------------------------------------------- */ + if (cnoOfFragsCheckpointed > 0) { + jam(); + completeLcpRoundLab(signal); + } else { + jam(); + sendLCP_COMPLETE_REP(signal, lcpId); + }//if + } + return; + }//if + tabptr.i = lcpFragOrd->tableId; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + + ndbrequire(tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || + tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE || + tabptr.p->tableStatus == Tablerec::TABLE_DEFINED); + + ndbrequire(getFragmentrec(signal, lcpFragOrd->fragmentId)); + + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + ndbrequire(!lcpPtr.p->lcpQueued); + if (c_lcpId < lcpFragOrd->lcpId) { + jam(); + /** + * A new LCP + */ + c_lcpId = lcpFragOrd->lcpId; + ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_IDLE); + setLogTail(signal, lcpFragOrd->keepGci); + ndbrequire(clcpCompletedState == LCP_IDLE); + clcpCompletedState = LCP_RUNNING; + }//if + cnoOfFragsCheckpointed++; + + if(tabptr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ + jam(); + LcpRecord::FragOrd fragOrd; + fragOrd.fragPtrI = fragptr.i; + fragOrd.lcpFragOrd = * lcpFragOrd; + sendLCP_FRAG_REP(signal, fragOrd); + return; + } + + if (lcpPtr.p->lcpState != LcpRecord::LCP_IDLE) { + ndbrequire(lcpPtr.p->lcpQueued == false); + lcpPtr.p->lcpQueued = true; + lcpPtr.p->queuedFragment.fragPtrI = fragptr.i; + lcpPtr.p->queuedFragment.lcpFragOrd = * lcpFragOrd; + return; + }//if + + lcpPtr.p->currentFragment.fragPtrI = fragptr.i; + lcpPtr.p->currentFragment.lcpFragOrd = * lcpFragOrd; + + sendLCP_FRAGIDREQ(signal); +}//Dblqh::execLCP_FRAGORD() + +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_PTR:LCP_STATE = WAIT_FRAGID + * -------------------------------------------------------------------------- + * WE NOW HAVE THE LOCAL FRAGMENTS THAT THE LOCAL CHECKPOINT WILL USE. + * -------------------------------------------------------------------------- */ +void Dblqh::execLCP_FRAGIDCONF(Signal* signal) +{ + UintR Tfragid[4]; + + jamEntry(); + + lcpPtr.i = signal->theData[0]; + + Uint32 TaccPtr = signal->theData[1]; + Uint32 noLocfrag = signal->theData[2]; + Tfragid[0] = signal->theData[3]; + Tfragid[1] = signal->theData[4]; + + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_FRAGID); + /* ------------------------------------------------------------------------ + * NO ERROR CHECKING OF TNO_LOCFRAG VALUE. OUT OF BOUND WILL IMPLY THAT AN + * INDEX OUT OF RANGE WILL CAUSE A SYSTEM RESTART WHICH IS DESIRED. + * ------------------------------------------------------------------------ */ + lcpPtr.p->lcpAccptr = TaccPtr; + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + ndbrequire(noLocfrag - 1 < 2); + for (Uint32 Tindex = 0; Tindex < noLocfrag; Tindex++) { + jam(); + Uint32 fragId = Tfragid[Tindex]; + /* ---------------------------------------------------------------------- + * THERE IS NO ERROR CHECKING ON PURPOSE. IT IS POSSIBLE TO CALCULATE HOW + * MANY LOCAL LCP RECORDS THERE SHOULD BE. IT SHOULD NEVER HAPPEN THAT + * THERE IS NO ONE FREE. IF THERE IS NO ONE IT WILL ALSO BE A POINTER + * OUT OF RANGE WHICH IS AN ERROR CODE IN ITSELF. REUSES ERROR HANDLING + * IN AXE VM. + * ---------------------------------------------------------------------- */ + seizeLcpLoc(signal); + initLcpLocAcc(signal, fragId); + seizeLcpLoc(signal); + initLcpLocTup(signal, fragId); + signal->theData[0] = lcpLocptr.i; + signal->theData[1] = cownref; + signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + signal->theData[3] = lcpLocptr.p->locFragid; + signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + signal->theData[5] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; + sendSignal(fragptr.p->tupBlockref, GSN_TUP_PREPLCPREQ, signal, 6, JBB); + }//for + lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_TUP_PREPLCP; + return; +}//Dblqh::execLCP_FRAGIDCONF() + +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_STATE = WAIT_TUPPREPLCP + * -------------------------------------------------------------------------- + * WE HAVE NOW PREPARED A LOCAL FRAGMENT IN TUP FOR LCP EXECUTION. + * -------------------------------------------------------------------------- */ +void Dblqh::execTUP_PREPLCPCONF(Signal* signal) +{ + UintR ttupPtr; + + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ttupPtr = signal->theData[1]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_TUP_PREPLCP); + + lcpLocptr.p->tupRef = ttupPtr; + lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; + checkLcpTupprep(signal); + if (lcpPtr.p->lcpState != LcpRecord::LCP_WAIT_HOLDOPS) { + jam(); + return; + }//if + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + do { + jam(); + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + lcpLocptr.p->lcpLocstate = LcpLocRecord::WAIT_LCPHOLDOP; + signal->theData[0] = lcpPtr.p->lcpAccptr; + signal->theData[1] = lcpLocptr.p->locFragid; + signal->theData[2] = 0; + signal->theData[3] = lcpLocptr.i; + sendSignal(fragptr.p->accBlockref, GSN_LCP_HOLDOPREQ, signal, 4, JBA); + lcpLocptr.i = lcpLocptr.p->nextLcpLoc; + } while (lcpLocptr.i != RNIL); + /* ------------------------------------------------------------------------ + * SET STATE ON FRAGMENT TO BLOCKED TO ENSURE THAT NO MORE OPERATIONS ARE + * STARTED FROM LQH IN TUP AND ACC UNTIL THE START CHECKPOINT HAS BEEN + * COMPLETED. ALSO SET THE LOCAL CHECKPOINT STATE TO WAIT FOR + * LCP_HOLDOPCONF + * ----------------------------------------------------------------------- */ + fragptr.p->fragStatus = Fragrecord::BLOCKED; + fragptr.p->fragActiveStatus = ZTRUE; + lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_HOLDOPS; + return; +}//Dblqh::execTUP_PREPLCPCONF() + +void Dblqh::execTUP_PREPLCPREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execTUP_PREPLCPREF() + +void Dblqh::execLCP_FRAGIDREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execLCP_FRAGIDREF() + +/* -------------------------------------------------------------------------- + * A NUMBER OF OPERATIONS THAT HAVE BEEN SET ON HOLD IN ACC. MOVE THOSE TO + * LIST OF BLOCKED ACC OPERATIONS. IF MORE OPERATIONS ARE BLOCKED GET THOSE + * OTHERWISE CONTINUE THE LOCAL CHECKPOINT BY REQUESTING TUP AND ACC TO + * WRITE THEIR START CHECKPOINT. + * -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = WAIT_LCPHOLDOP + * ------------------------------------------------------------------------- */ +/* ***************>> */ +/* LCP_HOLDOPCONF > */ +/* ***************>> */ +void Dblqh::execLCP_HOLDOPCONF(Signal* signal) +{ + UintR tnoHoldops; + Uint32 Tdata[23]; + Uint32 Tlength; + + jamEntry(); + lcpLocptr.i = signal->theData[0]; + Tlength = signal->theData[1]; + for (Uint32 i = 0; i < 23; i++) + Tdata[i] = signal->theData[i + 2]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_LCPHOLDOP); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS + * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ----------------------------------------------------------------------- */ + tnoHoldops = Tlength & 65535; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + ndbrequire(tnoHoldops <= 23); + for (Uint32 Tindex = 0; Tindex < tnoHoldops; Tindex++) { + jam(); + tcConnectptr.i = Tdata[Tindex]; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + moveActiveToAcc(signal); + }//for + if ((Tlength >> 16) == 1) { + jam(); + /* MORE HOLDOPS NEEDED */ + signal->theData[0] = lcpPtr.p->lcpAccptr; + signal->theData[1] = lcpLocptr.p->locFragid; + signal->theData[2] = 1; + signal->theData[3] = lcpLocptr.i; + sendSignal(fragptr.p->accBlockref, GSN_LCP_HOLDOPREQ, signal, 4, JBA); + return; + } else { + jam(); + + /* NO MORE HOLDOPS NEEDED */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::HOLDOP_READY; + checkLcpHoldop(signal); + + if (lcpPtr.p->lcpState == LcpRecord::LCP_WAIT_ACTIVE_FINISH) { + if (fragptr.p->activeList == RNIL) { + jam(); + /* ------------------------------------------------------------------ + * THERE ARE NO MORE ACTIVE OPERATIONS. IT IS NOW OK TO START THE + * LOCAL CHECKPOINT IN BOTH TUP AND ACC. + * ----------------------------------------------------------------- */ + sendStartLcp(signal); + lcpPtr.p->lcpState = LcpRecord::LCP_START_CHKP; + } else { + jam(); + // Set this to signal releaseActiveFrag + // that it should check to see if itäs time to call sendStartLcp + fragptr.p->lcpRef = lcpPtr.i; + }//if + }//if + }//if + + /* ----------------------- */ + /* ELSE */ + /* ------------------------------------------------------------------------ + * THERE ARE STILL MORE ACTIVE OPERATIONS. WAIT UNTIL THEY ARE FINSIHED. + * THIS IS DISCOVERED WHEN RELEASE_ACTIVE_FRAG IS EXECUTED. + * ------------------------------------------------------------------------ + * DO NOTHING, EXIT IS EXECUTED BELOW + * ----------------------------------------------------------------------- */ + return; +}//Dblqh::execLCP_HOLDOPCONF() + +/* ***************> */ +/* LCP_HOLDOPREF > */ +/* ***************> */ +void Dblqh::execLCP_HOLDOPREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execLCP_HOLDOPREF() + +/* ************************************************************************>> + * ACC_LCPSTARTED: Confirm that ACC started local checkpoint and undo + * logging is on. + * ************************************************************************>> + * -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = ACC_WAIT_STARTED + * ------------------------------------------------------------------------- */ +void Dblqh::execACC_LCPSTARTED(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS + * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ----------------------------------------------------------------------- */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_STARTED; + lcpStartedLab(signal); + return; +}//Dblqh::execACC_LCPSTARTED() + +/* ******************************************> */ +/* TUP_LCPSTARTED: Same as above but for TUP. */ +/* ******************************************> */ +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = TUP_WAIT_STARTED + * ------------------------------------------------------------------------- */ +void Dblqh::execTUP_LCPSTARTED(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE + * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ----------------------------------------------------------------------- */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_STARTED; + lcpStartedLab(signal); + return; +}//Dblqh::execTUP_LCPSTARTED() + +void Dblqh::lcpStartedLab(Signal* signal) +{ + checkLcpStarted(signal); + if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) { + jam(); + /* ---------------------------------------------------------------------- + * THE LOCAL CHECKPOINT HAS BEEN STARTED. IT IS NOW TIME TO + * RESTART THE TRANSACTIONS WHICH HAVE BEEN BLOCKED. + * --------------------------------------------------------------------- */ + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + /* ---------------------------------------------------------------------- + * UPDATE THE MAX_GCI_IN_LCP AND MAX_GCI_COMPLETED_IN_LCP NOW BEFORE + * ACTIVATING THE FRAGMENT AGAIN. + * --------------------------------------------------------------------- */ + ndbrequire(lcpPtr.p->currentFragment.lcpFragOrd.lcpNo < MAX_LCP_STORED); + fragptr.p->maxGciInLcp = fragptr.p->newestGci; + fragptr.p->maxGciCompletedInLcp = cnewestCompletedGci; + sendAccContOp(signal); /* START OPERATIONS IN ACC */ + moveAccActiveFrag(signal); /* MOVE FROM ACC BLOCKED LIST TO ACTIVE LIST + ON FRAGMENT */ + } + /*---------------*/ + /* ELSE */ + /*-------------------------------------------------------------------------*/ + /* THE LOCAL CHECKPOINT HAS NOT BEEN STARTED. EXIT AND WAIT FOR + * MORE SIGNALS */ + /*-------------------------------------------------------------------------*/ + /* DO NOTHING, EXIT IS EXECUTED BELOW */ + /*-------------------------------------------------------------------------*/ + return; +}//Dblqh::lcpStartedLab() + +/*--------------------------------------------------------------------------- + * ACC HAVE RESTARTED THE BLOCKED OPERATIONS AGAIN IN ONE FRAGMENT PART. + * IT IS NOW OUR TURN TO RESTART ALL OPERATIONS QUEUED IN LQH IF ALL + * FRAGMENT PARTS ARE COMPLETED. + *-------------------------------------------------------------------------- */ +void Dblqh::execACC_CONTOPCONF(Signal* signal) +{ + if(ERROR_INSERTED(5035) && signal->getSendersBlockRef() != reference()){ + sendSignalWithDelay(reference(), GSN_ACC_CONTOPCONF, signal, 1000, + signal->length()); + return; + } + + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + lcpLocptr.p->accContCounter = 1; + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + do { + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (lcpLocptr.p->accContCounter == 0) { + jam(); + return; + }//if + lcpLocptr.i = lcpLocptr.p->nextLcpLoc; + } while (lcpLocptr.i != RNIL); + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + restartOperationsLab(signal); + return; +}//Dblqh::execACC_CONTOPCONF() + +/* ********************************************************* */ +/* LQH_RESTART_OP: Restart operations after beeing blocked. */ +/* ********************************************************* */ +/*---------------------------------------------------------------------------*/ +/* PRECONDITION: FRAG_STATUS = BLOCKED AND LCP_STATE = STARTED */ +/*---------------------------------------------------------------------------*/ +void Dblqh::execLQH_RESTART_OP(Signal* signal) +{ + jamEntry(); + fragptr.i = signal->theData[0]; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + + lcpPtr.i = signal->theData[1]; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + ndbrequire(fragptr.p->fragStatus == Fragrecord::BLOCKED); + if (lcpPtr.p->lcpState == LcpRecord::LCP_STARTED) { + jam(); + /***********************************************************************/ + /* THIS SIGNAL CAN ONLY BE RECEIVED WHEN FRAGMENT IS BLOCKED AND + * THE LOCAL CHECKPOINT HAS BEEN STARTED. THE BLOCKING WILL BE + * REMOVED AS SOON AS ALL OPERATIONS HAVE BEEN STARTED. + ***********************************************************************/ + restartOperationsLab(signal); + } else if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) { + jam(); + /*******************************************************************> + * THE CHECKPOINT IS COMPLETED BUT HAS NOT YET STARTED UP + * ALL OPERATIONS AGAIN. + * WE PERFORM THIS START-UP BEFORE CONTINUING WITH THE NEXT + * FRAGMENT OF THE LOCAL CHECKPOINT TO AVOID ANY STRANGE ERRORS. + *******************************************************************> */ + restartOperationsLab(signal); + } else { + ndbrequire(false); + } +}//Dblqh::execLQH_RESTART_OP() + +void Dblqh::restartOperationsLab(Signal* signal) +{ + Uint32 loopCount = 0; + tcConnectptr.i = fragptr.p->firstWaitQueue; + do { + if (tcConnectptr.i != RNIL) { + jam(); +/*---------------------------------------------------------------------------*/ +/* START UP THE TRANSACTION AGAIN. WE START IT AS A SEPARATE SIGNAL. */ +/*---------------------------------------------------------------------------*/ + signal->theData[0] = ZRESTART_OPERATIONS_AFTER_STOP; + signal->theData[1] = tcConnectptr.i; + signal->theData[2] = fragptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 3, JBB); + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + tcConnectptr.i = tcConnectptr.p->nextTc; + } else { + jam(); +/*--------------------------------------------------------------------------*/ +/* NO MORE OPERATIONS TO RESTART. WE CAN NOW RESET THE STATE TO ACTIVE AND */ +/* RESTART NORMAL ACTIVITIES ON THE FRAGMENT WHILE THE FUZZY PART OF THE */ +/* LOCAL CHECKPOINT IS COMPLETING. */ +/* IF THE CHECKPOINT WAS COMPLETED ALREADY ON THIS FRAGMENT WE PROCEED WITH */ +/* THE NEXT FRAGMENT NOW THAT WE HAVE COMPLETED THIS CHECKPOINT. */ +/*--------------------------------------------------------------------------*/ + fragptr.p->fragStatus = Fragrecord::FSACTIVE; + if (lcpPtr.p->lcpState == LcpRecord::LCP_BLOCKED_COMP) { + jam(); + contChkpNextFragLab(signal); + return; + }//if + return; + }//if + loopCount++; + if (loopCount > 16) { + jam(); + signal->theData[0] = fragptr.i; + signal->theData[1] = lcpPtr.i; + sendSignal(cownref, GSN_LQH_RESTART_OP, signal, 2, JBB); + return; + }//if + } while (1); +}//Dblqh::restartOperationsLab() + +void Dblqh::restartOperationsAfterStopLab(Signal* signal) +{ + /*------------------------------------------------------------------------- + * WHEN ARRIVING HERE THE OPERATION IS ALREADY SET IN THE ACTIVE LIST. + * THUS WE CAN IMMEDIATELY CALL THE METHODS THAT EXECUTE FROM WHERE + * THE OPERATION WAS STOPPED. + *------------------------------------------------------------------------ */ + switch (tcConnectptr.p->transactionState) { + case TcConnectionrec::STOPPED: + jam(); + /*----------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND ACCKEYREQ + *---------------------------------------------------------------------- */ + prepareContinueAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::COMMIT_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND ACC_COMMITREQ + * --------------------------------------------------------------------- */ + releaseActiveFrag(signal); + commitContinueAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::ABORT_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND ACC_ABORTREQ + * --------------------------------------------------------------------- */ + abortContinueAfterBlockedLab(signal, true); + return; + break; + case TcConnectionrec::COPY_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT + * --------------------------------------------------------------------- */ + continueCopyAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::COPY_FIRST_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING COPY FRAGMENT + * --------------------------------------------------------------------- */ + continueFirstCopyAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::SCAN_FIRST_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN + * --------------------------------------------------------------------- */ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + continueFirstScanAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::SCAN_CHECK_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN + * --------------------------------------------------------------------- */ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + continueAfterCheckLcpStopBlocked(signal); + return; + break; + case TcConnectionrec::SCAN_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING SCAN + * --------------------------------------------------------------------- */ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + continueScanAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::SCAN_RELEASE_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING RELEASE + * LOCKS IN SCAN + * --------------------------------------------------------------------- */ + tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED; + continueScanReleaseAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::SCAN_CLOSE_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF SCAN + * --------------------------------------------------------------------- */ + continueCloseScanAfterBlockedLab(signal); + return; + break; + case TcConnectionrec::COPY_CLOSE_STOPPED: + jam(); + /* ---------------------------------------------------------------------- + * STOPPED BEFORE TRYING TO SEND NEXT_SCANREQ DURING CLOSE OF COPY + * --------------------------------------------------------------------- */ + continueCloseCopyAfterBlockedLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch +}//Dblqh::restartOperationsAfterStopLab() + +/* *************** */ +/* ACC_LCPCONF > */ +/* *************** */ +/*--------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = ACC_STARTED + *-------------------------------------------------------------------------- */ +void Dblqh::execACC_LCPCONF(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN + * THIS REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A + * SYSTEM RESTART. + * ----------------------------------------------------------------------- */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_COMPLETED; + lcpCompletedLab(signal); + return; +}//Dblqh::execACC_LCPCONF() + +/* *************** */ +/* TUP_LCPCONF > */ +/* *************** */ +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = TUP_STARTED + * ------------------------------------------------------------------------- */ +void Dblqh::execTUP_LCPCONF(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_STARTED); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS + * REFERENCE WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ----------------------------------------------------------------------- */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_COMPLETED; + lcpCompletedLab(signal); + return; +}//Dblqh::execTUP_LCPCONF() + +void Dblqh::lcpCompletedLab(Signal* signal) +{ + checkLcpCompleted(signal); + if (lcpPtr.p->lcpState != LcpRecord::LCP_COMPLETED) { + jam(); + /* ---------------------------------------------------------------------- + * THE LOCAL CHECKPOINT HAS NOT BEEN COMPLETED, EXIT & WAIT + * FOR MORE SIGNALS + * --------------------------------------------------------------------- */ + return; + }//if + /* ------------------------------------------------------------------------ + * THE LOCAL CHECKPOINT HAS BEEN COMPLETED. IT IS NOW TIME TO START + * A LOCAL CHECKPOINT ON THE NEXT FRAGMENT OR COMPLETE THIS LCP ROUND. + * ------------------------------------------------------------------------ + * WE START BY SENDING LCP_REPORT TO DIH TO REPORT THE COMPLETED LCP. + * TO CATER FOR NODE CRASHES WE SEND IT IN PARALLEL TO ALL NODES. + * ----------------------------------------------------------------------- */ + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->fragActiveStatus = ZFALSE; + + contChkpNextFragLab(signal); + return; +}//Dblqh::lcpCompletedLab() + +void +Dblqh::sendLCP_FRAG_REP(Signal * signal, + const LcpRecord::FragOrd & fragOrd) const { + + FragrecordPtr fragPtr; + fragPtr.i = fragOrd.fragPtrI; + ptrCheckGuard(fragPtr, cfragrecFileSize, fragrecord); + + ndbrequire(fragOrd.lcpFragOrd.lcpNo < MAX_LCP_STORED); + LcpFragRep * const lcpReport = (LcpFragRep *)&signal->theData[0]; + lcpReport->nodeId = cownNodeid; + lcpReport->lcpId = fragOrd.lcpFragOrd.lcpId; + lcpReport->lcpNo = fragOrd.lcpFragOrd.lcpNo; + lcpReport->tableId = fragOrd.lcpFragOrd.tableId; + lcpReport->fragId = fragOrd.lcpFragOrd.fragmentId; + lcpReport->maxGciCompleted = fragPtr.p->maxGciCompletedInLcp; + lcpReport->maxGciStarted = fragPtr.p->maxGciInLcp; + + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + Uint32 nodeId = cnodeData[i]; + if(cnodeStatus[i] == ZNODE_UP){ + jam(); + BlockReference Tblockref = calcDihBlockRef(nodeId); + sendSignal(Tblockref, GSN_LCP_FRAG_REP, signal, + LcpFragRep::SignalLength, JBB); + }//if + }//for +} + +void Dblqh::contChkpNextFragLab(Signal* signal) +{ + /* ------------------------------------------------------------------------ + * UPDATE THE LATEST LOCAL CHECKPOINT COMPLETED ON FRAGMENT. + * UPDATE THE LCP_ID OF THIS CHECKPOINT. + * REMOVE THE LINK BETWEEN THE FRAGMENT RECORD AND THE LCP RECORD. + * ----------------------------------------------------------------------- */ + if (fragptr.p->fragStatus == Fragrecord::BLOCKED) { + jam(); + /** + * LCP of fragment complete + * but restarting of operations isn't + */ + lcpPtr.p->lcpState = LcpRecord::LCP_BLOCKED_COMP; + //restartOperationsLab(signal); + return; + }//if + + /** + * Send rep when fragment is done + unblocked + */ + sendLCP_FRAG_REP(signal, lcpPtr.p->currentFragment); + + /* ------------------------------------------------------------------------ + * WE ALSO RELEASE THE LOCAL LCP RECORDS. + * ----------------------------------------------------------------------- */ + releaseLocalLcps(signal); + if (lcpPtr.p->lcpQueued) { + jam(); + /* ---------------------------------------------------------------------- + * Transfer the state from the queued to the active LCP. + * --------------------------------------------------------------------- */ + lcpPtr.p->lcpQueued = false; + lcpPtr.p->currentFragment = lcpPtr.p->queuedFragment; + + /* ---------------------------------------------------------------------- + * START THE QUEUED LOCAL CHECKPOINT. + * --------------------------------------------------------------------- */ + sendLCP_FRAGIDREQ(signal); + return; + }//if + + lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; + if (lcpPtr.p->lastFragmentFlag){ + jam(); + /* ---------------------------------------------------------------------- + * NOW THE COMPLETE LOCAL CHECKPOINT ROUND IS COMPLETED. + * --------------------------------------------------------------------- */ + completeLcpRoundLab(signal); + return; + }//if + + if (lcpPtr.p->reportEmpty) { + jam(); + sendEMPTY_LCP_CONF(signal, false); + }//if + return; +}//Dblqh::contChkpNextFragLab() + +void Dblqh::sendLCP_FRAGIDREQ(Signal* signal) +{ + ndbrequire(lcpPtr.p->firstLcpLocTup == RNIL); + ndbrequire(lcpPtr.p->firstLcpLocAcc == RNIL); + + TablerecPtr tabPtr; + tabPtr.i = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + ptrAss(tabPtr, tablerec); + if(tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_ONGOING || + tabPtr.p->tableStatus == Tablerec::PREP_DROP_TABLE_DONE){ + jam(); + /** + * Fake that the fragment is done + */ + lcpCompletedLab(signal); + return; + } + + ndbrequire(tabPtr.p->tableStatus == Tablerec::TABLE_DEFINED); + + lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_FRAGID; + signal->theData[0] = lcpPtr.i; + signal->theData[1] = cownref; + signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; + signal->theData[5] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; + sendSignal(fragptr.p->accBlockref, GSN_LCP_FRAGIDREQ, signal, 6, JBB); +}//Dblqh::sendLCP_FRAGIDREQ() + +void Dblqh::sendEMPTY_LCP_CONF(Signal* signal, bool idle) +{ + + EmptyLcpConf * const rep = (EmptyLcpConf*)&signal->theData[0]; + /* ---------------------------------------------------------------------- + * We have been requested to report when there are no more local + * waiting to be started or ongoing. In this signal we also report + * the last completed fragments state. + * ---------------------------------------------------------------------- */ + rep->senderNodeId = getOwnNodeId(); + if(!idle){ + jam(); + rep->idle = 0 ; + rep->tableId = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + rep->fragmentId = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; + rep->lcpNo = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + rep->lcpId = lcpPtr.p->currentFragment.lcpFragOrd.lcpId; + } else { + jam(); + rep->idle = 1; + rep->tableId = ~0; + rep->fragmentId = ~0; + rep->lcpNo = ~0; + rep->lcpId = c_lcpId; + } + + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + Uint32 nodeId = cnodeData[i]; + if (lcpPtr.p->m_EMPTY_LCP_REQ.get(nodeId)) { + jam(); + + BlockReference blockref = calcDihBlockRef(nodeId); + sendSignal(blockref, GSN_EMPTY_LCP_CONF, signal, + EmptyLcpConf::SignalLength, JBB); + }//if + }//for + + lcpPtr.p->reportEmpty = false; + lcpPtr.p->m_EMPTY_LCP_REQ.clear(); +}//Dblqh::sendEMPTY_LCPCONF() + +void Dblqh::execACC_LCPREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execACC_LCPREF() + +void Dblqh::execTUP_LCPREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execTUP_LCPREF() + +/* -------------------------------------------------------------------------- + * THE LOCAL CHECKPOINT ROUND IS NOW COMPLETED. SEND COMPLETED MESSAGE + * TO THE MASTER DIH. + * ------------------------------------------------------------------------- */ +void Dblqh::completeLcpRoundLab(Signal* signal) +{ + clcpCompletedState = LCP_CLOSE_STARTED; + signal->theData[0] = caccBlockref; + signal->theData[1] = cownref; + sendSignal(caccBlockref, GSN_END_LCPREQ, signal, 2, JBB); + signal->theData[0] = ctupBlockref; + signal->theData[1] = cownref; + sendSignal(ctupBlockref, GSN_END_LCPREQ, signal, 2, JBB); + return; +}//Dblqh::completeLcpRoundLab() + +void Dblqh::execEND_LCPCONF(Signal* signal) +{ + jamEntry(); + BlockReference userpointer = signal->theData[0]; + if (userpointer == caccBlockref) { + if (clcpCompletedState == LCP_CLOSE_STARTED) { + jam(); + clcpCompletedState = ACC_LCP_CLOSE_COMPLETED; + return; + } else { + jam(); + ndbrequire(clcpCompletedState == TUP_LCP_CLOSE_COMPLETED); + clcpCompletedState = LCP_IDLE; + }//if + } else { + ndbrequire(userpointer == ctupBlockref); + if (clcpCompletedState == LCP_CLOSE_STARTED) { + jam(); + clcpCompletedState = TUP_LCP_CLOSE_COMPLETED; + return; + } else { + jam(); + ndbrequire(clcpCompletedState == ACC_LCP_CLOSE_COMPLETED); + clcpCompletedState = LCP_IDLE; + }//if + }//if + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + sendLCP_COMPLETE_REP(signal, lcpPtr.p->currentFragment.lcpFragOrd.lcpId); +}//Dblqh::execEND_LCPCONF() + +void Dblqh::sendLCP_COMPLETE_REP(Signal* signal, Uint32 lcpId) +{ + cnoOfFragsCheckpointed = 0; + ndbrequire((cnoOfNodes - 1) < (MAX_NDB_NODES - 1)); + /* ------------------------------------------------------------------------ + * WE SEND COMP_LCP_ROUND TO ALL NODES TO PREPARE FOR NODE CRASHES. + * ----------------------------------------------------------------------- */ + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + lcpPtr.p->lastFragmentFlag = false; + + LcpCompleteRep* rep = (LcpCompleteRep*)signal->getDataPtrSend(); + rep->nodeId = getOwnNodeId(); + rep->lcpId = lcpId; + rep->blockNo = DBLQH; + + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + Uint32 nodeId = cnodeData[i]; + if(cnodeStatus[i] == ZNODE_UP){ + jam(); + + BlockReference blockref = calcDihBlockRef(nodeId); + sendSignal(blockref, GSN_LCP_COMPLETE_REP, signal, + LcpCompleteRep::SignalLength, JBB); + }//if + }//for + + if(lcpPtr.p->reportEmpty){ + jam(); + sendEMPTY_LCP_CONF(signal, true); + } + return; +}//Dblqh::sendCOMP_LCP_ROUND() + +/* ========================================================================== + * ======= CHECK IF ALL PARTS OF A LOCAL CHECKPOINT ARE COMPLETED ======= + * + * SUBROUTINE SHORT NAME = CLC + * ========================================================================= */ +void Dblqh::checkLcpCompleted(Signal* signal) +{ + LcpLocRecordPtr clcLcpLocptr; + + clcLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + while (clcLcpLocptr.i != RNIL) { + ptrCheckGuard(clcLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (clcLcpLocptr.p->lcpLocstate != LcpLocRecord::ACC_COMPLETED) { + jam(); + ndbrequire((clcLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED) || + (clcLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED)); + return; + }//if + clcLcpLocptr.i = clcLcpLocptr.p->nextLcpLoc; + } + + clcLcpLocptr.i = lcpPtr.p->firstLcpLocTup; + while (clcLcpLocptr.i != RNIL){ + ptrCheckGuard(clcLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (clcLcpLocptr.p->lcpLocstate != LcpLocRecord::TUP_COMPLETED) { + jam(); + ndbrequire((clcLcpLocptr.p->lcpLocstate==LcpLocRecord::TUP_WAIT_STARTED) + ||(clcLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_STARTED)); + return; + }//if + clcLcpLocptr.i = clcLcpLocptr.p->nextLcpLoc; + } + + lcpPtr.p->lcpState = LcpRecord::LCP_COMPLETED; +}//Dblqh::checkLcpCompleted() + +/* ========================================================================== + * ======= CHECK IF ALL HOLD OPERATIONS ARE COMPLETED ======= + * + * SUBROUTINE SHORT NAME = CHO + * ========================================================================= */ +void Dblqh::checkLcpHoldop(Signal* signal) +{ + LcpLocRecordPtr choLcpLocptr; + + choLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + do { + ptrCheckGuard(choLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (choLcpLocptr.p->lcpLocstate != LcpLocRecord::HOLDOP_READY) { + ndbrequire(choLcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_LCPHOLDOP); + return; + }//if + choLcpLocptr.i = choLcpLocptr.p->nextLcpLoc; + } while (choLcpLocptr.i != RNIL); + lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_ACTIVE_FINISH; +}//Dblqh::checkLcpHoldop() + +/* ========================================================================== + * ======= CHECK IF ALL PARTS OF A LOCAL CHECKPOINT ARE STARTED ======= + * + * SUBROUTINE SHORT NAME = CLS + * ========================================================================== */ +void Dblqh::checkLcpStarted(Signal* signal) +{ + LcpLocRecordPtr clsLcpLocptr; + + terrorCode = ZOK; + clsLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + int i = 0; + do { + ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_WAIT_STARTED){ + return; + }//if + clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; + i++; + } while (clsLcpLocptr.i != RNIL); + + i = 0; + clsLcpLocptr.i = lcpPtr.p->firstLcpLocTup; + do { + ptrCheckGuard(clsLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (clsLcpLocptr.p->lcpLocstate == LcpLocRecord::TUP_WAIT_STARTED){ + return; + }//if + clsLcpLocptr.i = clsLcpLocptr.p->nextLcpLoc; + i++; + } while (clsLcpLocptr.i != RNIL); + lcpPtr.p->lcpState = LcpRecord::LCP_STARTED; +}//Dblqh::checkLcpStarted() + +/* ========================================================================== + * ======= CHECK IF ALL PREPARE TUP OPERATIONS ARE COMPLETED ======= + * + * SUBROUTINE SHORT NAME = CLT + * ========================================================================== */ +void Dblqh::checkLcpTupprep(Signal* signal) +{ + LcpLocRecordPtr cltLcpLocptr; + cltLcpLocptr.i = lcpPtr.p->firstLcpLocTup; + do { + ptrCheckGuard(cltLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (cltLcpLocptr.p->lcpLocstate != LcpLocRecord::IDLE) { + ndbrequire(cltLcpLocptr.p->lcpLocstate == LcpLocRecord::WAIT_TUP_PREPLCP); + return; + }//if + cltLcpLocptr.i = cltLcpLocptr.p->nextLcpLoc; + } while (cltLcpLocptr.i != RNIL); + lcpPtr.p->lcpState = LcpRecord::LCP_WAIT_HOLDOPS; +}//Dblqh::checkLcpTupprep() + +/* ========================================================================== + * ======= INITIATE LCP LOCAL RECORD USED TOWARDS ACC ======= + * + * ========================================================================== */ +void Dblqh::initLcpLocAcc(Signal* signal, Uint32 fragId) +{ + lcpLocptr.p->nextLcpLoc = lcpPtr.p->firstLcpLocAcc; + lcpPtr.p->firstLcpLocAcc = lcpLocptr.i; + lcpLocptr.p->locFragid = fragId; + lcpLocptr.p->waitingBlock = LcpLocRecord::ACC; + lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; + lcpLocptr.p->masterLcpRec = lcpPtr.i; + lcpLocptr.p->tupRef = RNIL; +}//Dblqh::initLcpLocAcc() + +/* ========================================================================== + * ======= INITIATE LCP LOCAL RECORD USED TOWARDS TUP ======= + * + * ========================================================================== */ +void Dblqh::initLcpLocTup(Signal* signal, Uint32 fragId) +{ + lcpLocptr.p->nextLcpLoc = lcpPtr.p->firstLcpLocTup; + lcpPtr.p->firstLcpLocTup = lcpLocptr.i; + lcpLocptr.p->locFragid = fragId; + lcpLocptr.p->waitingBlock = LcpLocRecord::TUP; + lcpLocptr.p->lcpLocstate = LcpLocRecord::WAIT_TUP_PREPLCP; + lcpLocptr.p->masterLcpRec = lcpPtr.i; + lcpLocptr.p->tupRef = RNIL; +}//Dblqh::initLcpLocTup() + +/* -------------------------------------------------------------------------- + * ------- MOVE OPERATION FROM ACC WAITING LIST ON FRAGMENT ------- + * ------- TO ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME = MAA + * -------------------------------------------------------------------------- */ +void Dblqh::moveAccActiveFrag(Signal* signal) +{ + UintR maaTcNextConnectptr; + + tcConnectptr.i = fragptr.p->accBlockedList; + fragptr.p->accBlockedList = RNIL; + /* ------------------------------------------------------------------------ + * WE WILL MOVE ALL RECORDS FROM THE ACC BLOCKED LIST AT ONCE. + * ------------------------------------------------------------------------ */ + while (tcConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + maaTcNextConnectptr = tcConnectptr.p->nextTc; + ndbrequire(tcConnectptr.p->listState == TcConnectionrec::ACC_BLOCK_LIST); + tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; + linkActiveFrag(signal); + tcConnectptr.i = maaTcNextConnectptr; + }//while +}//Dblqh::moveAccActiveFrag() + +/* -------------------------------------------------------------------------- + * ------- MOVE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- + * ------- TO ACC BLOCKED LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME = MAT + * -------------------------------------------------------------------------- */ +void Dblqh::moveActiveToAcc(Signal* signal) +{ + TcConnectionrecPtr matTcNextConnectptr; + + releaseActiveList(signal); + /* ------------------------------------------------------------------------ + * PUT OPERATION RECORD FIRST IN ACC BLOCKED LIST. + * ------------------------------------------------------------------------ */ + matTcNextConnectptr.i = fragptr.p->accBlockedList; + tcConnectptr.p->nextTc = matTcNextConnectptr.i; + tcConnectptr.p->prevTc = RNIL; + tcConnectptr.p->listState = TcConnectionrec::ACC_BLOCK_LIST; + fragptr.p->accBlockedList = tcConnectptr.i; + if (matTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(matTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + matTcNextConnectptr.p->prevTc = tcConnectptr.i; + }//if +}//Dblqh::moveActiveToAcc() + +/* ------------------------------------------------------------------------- */ +/* ---- RELEASE LOCAL LCP RECORDS AFTER COMPLETION OF A LOCAL CHECKPOINT---- */ +/* */ +/* SUBROUTINE SHORT NAME = RLL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::releaseLocalLcps(Signal* signal) +{ + lcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + while (lcpLocptr.i != RNIL){ + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + Uint32 tmp = lcpLocptr.p->nextLcpLoc; + releaseLcpLoc(signal); + lcpLocptr.i = tmp; + } + lcpPtr.p->firstLcpLocAcc = RNIL; + + lcpLocptr.i = lcpPtr.p->firstLcpLocTup; + while (lcpLocptr.i != RNIL){ + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + Uint32 tmp = lcpLocptr.p->nextLcpLoc; + releaseLcpLoc(signal); + lcpLocptr.i = tmp; + } + lcpPtr.p->firstLcpLocTup = RNIL; + +}//Dblqh::releaseLocalLcps() + +/* ------------------------------------------------------------------------- */ +/* ------- SEIZE LCP LOCAL RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::seizeLcpLoc(Signal* signal) +{ + lcpLocptr.i = cfirstfreeLcpLoc; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + cfirstfreeLcpLoc = lcpLocptr.p->nextLcpLoc; + lcpLocptr.p->nextLcpLoc = RNIL; +}//Dblqh::seizeLcpLoc() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND ACC_CONT_OP ------- */ +/* */ +/* INPUT: LCP_PTR LOCAL CHECKPOINT RECORD */ +/* FRAGPTR FRAGMENT RECORD */ +/* */ +/* SUBROUTINE SHORT NAME = SAC */ +/* ------------------------------------------------------------------------- */ +void Dblqh::sendAccContOp(Signal* signal) +{ + LcpLocRecordPtr sacLcpLocptr; + + int count = 0; + sacLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + do { + ptrCheckGuard(sacLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + sacLcpLocptr.p->accContCounter = 0; + if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_STARTED){ + /* ------------------------------------------------------------------- */ + /*SEND START OPERATIONS TO ACC AGAIN */ + /* ------------------------------------------------------------------- */ + signal->theData[0] = lcpPtr.p->lcpAccptr; + signal->theData[1] = sacLcpLocptr.p->locFragid; + sendSignal(fragptr.p->accBlockref, GSN_ACC_CONTOPREQ, signal, 2, JBA); + count++; + } else if(sacLcpLocptr.p->lcpLocstate == LcpLocRecord::ACC_COMPLETED){ + signal->theData[0] = sacLcpLocptr.i; + sendSignal(reference(), GSN_ACC_CONTOPCONF, signal, 1, JBB); + } else { + ndbrequire(false); + } + sacLcpLocptr.i = sacLcpLocptr.p->nextLcpLoc; + } while (sacLcpLocptr.i != RNIL); + +}//Dblqh::sendAccContOp() + +/* ------------------------------------------------------------------------- */ +/* ------- SEND ACC_LCPREQ AND TUP_LCPREQ ------- */ +/* */ +/* INPUT: LCP_PTR LOCAL CHECKPOINT RECORD */ +/* FRAGPTR FRAGMENT RECORD */ +/* SUBROUTINE SHORT NAME = STL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::sendStartLcp(Signal* signal) +{ + LcpLocRecordPtr stlLcpLocptr; + stlLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; + do { + jam(); + ptrCheckGuard(stlLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + stlLcpLocptr.p->lcpLocstate = LcpLocRecord::ACC_WAIT_STARTED; + signal->theData[0] = lcpPtr.p->lcpAccptr; + signal->theData[1] = stlLcpLocptr.i; + signal->theData[2] = stlLcpLocptr.p->locFragid; + sendSignal(fragptr.p->accBlockref, GSN_ACC_LCPREQ, signal, 3, JBA); + stlLcpLocptr.i = stlLcpLocptr.p->nextLcpLoc; + } while (stlLcpLocptr.i != RNIL); + + stlLcpLocptr.i = lcpPtr.p->firstLcpLocTup; + do { + jam(); + ptrCheckGuard(stlLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + stlLcpLocptr.p->lcpLocstate = LcpLocRecord::TUP_WAIT_STARTED; + signal->theData[0] = stlLcpLocptr.i; + signal->theData[1] = cownref; + signal->theData[2] = stlLcpLocptr.p->tupRef; + sendSignal(fragptr.p->tupBlockref, GSN_TUP_LCPREQ, signal, 3, JBA); + stlLcpLocptr.i = stlLcpLocptr.p->nextLcpLoc; + } while (stlLcpLocptr.i != RNIL); +}//Dblqh::sendStartLcp() + +/* ------------------------------------------------------------------------- */ +/* ------- SET THE LOG TAIL IN THE LOG FILES ------- */ +/* */ +/*THIS SUBROUTINE HAVE BEEN BUGGY AND IS RATHER COMPLEX. IT IS IMPORTANT TO */ +/*REMEMBER THAT WE SEARCH FROM THE TAIL UNTIL WE REACH THE HEAD (CURRENT). */ +/*THE TAIL AND HEAD CAN BE ON THE SAME MBYTE. WE SEARCH UNTIL WE FIND A MBYTE*/ +/*THAT WE NEED TO KEEP. WE THEN SET THE TAIL TO BE THE PREVIOUS. IF WE DO */ +/*NOT FIND A MBYTE THAT WE NEED TO KEEP UNTIL WE REACH THE HEAD THEN WE USE */ +/*THE HEAD AS TAIL. FINALLY WE HAVE TO MOVE BACK THE TAIL TO ALSO INCLUDE */ +/*ALL PREPARE RECORDS. THIS MEANS THAT LONG-LIVED TRANSACTIONS ARE DANGEROUS */ +/*FOR SHORT LOGS. */ +/* ------------------------------------------------------------------------- */ + +// this function has not been verified yet +Uint32 Dblqh::remainingLogSize(const LogFileRecordPtr &sltCurrLogFilePtr, + const LogPartRecordPtr &sltLogPartPtr) +{ + Uint32 hf = sltCurrLogFilePtr.p->fileNo*ZNO_MBYTES_IN_FILE+sltCurrLogFilePtr.p->currentMbyte; + Uint32 tf = sltLogPartPtr.p->logTailFileNo*ZNO_MBYTES_IN_FILE+sltLogPartPtr.p->logTailMbyte; + Uint32 sz = sltLogPartPtr.p->noLogFiles*ZNO_MBYTES_IN_FILE; + if (tf > hf) hf += sz; + return sz-(hf-tf); +} + +void Dblqh::setLogTail(Signal* signal, Uint32 keepGci) +{ + LogPartRecordPtr sltLogPartPtr; + LogFileRecordPtr sltLogFilePtr; +#if 0 + LogFileRecordPtr sltCurrLogFilePtr; +#endif + UintR tsltMbyte; + UintR tsltStartMbyte; + UintR tsltIndex; + UintR tsltFlag; + + for (sltLogPartPtr.i = 0; sltLogPartPtr.i < 4; sltLogPartPtr.i++) { + jam(); + ptrAss(sltLogPartPtr, logPartRecord); + findLogfile(signal, sltLogPartPtr.p->logTailFileNo, + sltLogPartPtr, &sltLogFilePtr); + +#if 0 + sltCurrLogFilePtr.i = sltLogPartPtr.p->currentLogfile; + ptrCheckGuard(sltCurrLogFilePtr, clogFileFileSize, logFileRecord); + infoEvent("setLogTail: Available log file %d size = %d[mbytes]+%d[words]", sltLogPartPtr.i, + remainingLogSize(sltCurrLogFilePtr, sltLogPartPtr), sltCurrLogFilePtr.p->remainingWordsInMbyte); +#endif + + tsltMbyte = sltLogPartPtr.p->logTailMbyte; + tsltStartMbyte = tsltMbyte; + tsltFlag = ZFALSE; + if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) { +/* ------------------------------------------------------------------------- */ +/*THE LOG AND THE TAIL IS ALREADY IN THE SAME FILE. */ +/* ------------------------------------------------------------------------- */ + if (sltLogFilePtr.p->currentMbyte >= sltLogPartPtr.p->logTailMbyte) { + jam(); +/* ------------------------------------------------------------------------- */ +/*THE CURRENT MBYTE IS AHEAD OF OR AT THE TAIL. THUS WE WILL ONLY LOOK FOR */ +/*THE TAIL UNTIL WE REACH THE CURRENT MBYTE WHICH IS IN THIS LOG FILE. */ +/*IF THE LOG TAIL IS AHEAD OF THE CURRENT MBYTE BUT IN THE SAME LOG FILE */ +/*THEN WE HAVE TO SEARCH THROUGH ALL FILES BEFORE WE COME TO THE CURRENT */ +/*MBYTE. WE ALWAYS STOP WHEN WE COME TO THE CURRENT MBYTE SINCE THE TAIL */ +/*CAN NEVER BE BEFORE THE HEAD. */ +/* ------------------------------------------------------------------------- */ + tsltFlag = ZTRUE; + }//if + }//if + +/* ------------------------------------------------------------------------- */ +/*NOW START SEARCHING FOR THE NEW TAIL, STARTING AT THE CURRENT TAIL AND */ +/*PROCEEDING UNTIL WE FIND A MBYTE WHICH IS NEEDED TO KEEP OR UNTIL WE REACH */ +/*CURRENT MBYTE (THE HEAD). */ +/* ------------------------------------------------------------------------- */ + SLT_LOOP: + for (tsltIndex = tsltStartMbyte; + tsltIndex <= ZNO_MBYTES_IN_FILE - 1; + tsltIndex++) { + if (sltLogFilePtr.p->logMaxGciStarted[tsltIndex] >= keepGci) { +/* ------------------------------------------------------------------------- */ +/*WE ARE NOT ALLOWED TO STEP THE LOG ANY FURTHER AHEAD */ +/*SET THE NEW LOG TAIL AND CONTINUE WITH NEXT LOG PART. */ +/*THIS MBYTE IS NOT TO BE INCLUDED SO WE NEED TO STEP BACK ONE MBYTE. */ +/* ------------------------------------------------------------------------- */ + if (tsltIndex != 0) { + jam(); + tsltMbyte = tsltIndex - 1; + } else { + jam(); +/* ------------------------------------------------------------------------- */ +/*STEPPING BACK INCLUDES ALSO STEPPING BACK TO THE PREVIOUS LOG FILE. */ +/* ------------------------------------------------------------------------- */ + tsltMbyte = ZNO_MBYTES_IN_FILE - 1; + sltLogFilePtr.i = sltLogFilePtr.p->prevLogFile; + ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord); + }//if + goto SLT_BREAK; + } else { + jam(); + if (tsltFlag == ZTRUE) { +/* ------------------------------------------------------------------------- */ +/*WE ARE IN THE SAME FILE AS THE CURRENT MBYTE AND WE CAN REACH THE CURRENT */ +/*MBYTE BEFORE WE REACH A NEW TAIL. */ +/* ------------------------------------------------------------------------- */ + if (tsltIndex == sltLogFilePtr.p->currentMbyte) { + jam(); +/* ------------------------------------------------------------------------- */ +/*THE TAIL OF THE LOG IS ACTUALLY WITHIN THE CURRENT MBYTE. THUS WE SET THE */ +/*LOG TAIL TO BE THE CURRENT MBYTE. */ +/* ------------------------------------------------------------------------- */ + tsltMbyte = sltLogFilePtr.p->currentMbyte; + goto SLT_BREAK; + }//if + }//if + }//if + }//for + sltLogFilePtr.i = sltLogFilePtr.p->nextLogFile; + ptrCheckGuard(sltLogFilePtr, clogFileFileSize, logFileRecord); + if (sltLogFilePtr.i == sltLogPartPtr.p->currentLogfile) { + jam(); + tsltFlag = ZTRUE; + }//if + tsltStartMbyte = 0; + goto SLT_LOOP; + SLT_BREAK: + jam(); + { + UintR ToldTailFileNo = sltLogPartPtr.p->logTailFileNo; + UintR ToldTailMByte = sltLogPartPtr.p->logTailMbyte; + + arrGuard(tsltMbyte, 16); + sltLogPartPtr.p->logTailFileNo = + sltLogFilePtr.p->logLastPrepRef[tsltMbyte] >> 16; +/* ------------------------------------------------------------------------- */ +/*SINCE LOG_MAX_GCI_STARTED ONLY KEEP TRACK OF COMMIT LOG RECORDS WE ALSO */ +/*HAVE TO STEP BACK THE TAIL SO THAT WE INCLUDE ALL PREPARE RECORDS */ +/*NEEDED FOR THOSE COMMIT RECORDS IN THIS MBYTE. THIS IS A RATHER */ +/*CONSERVATIVE APPROACH BUT IT WORKS. */ +/* ------------------------------------------------------------------------- */ + sltLogPartPtr.p->logTailMbyte = + sltLogFilePtr.p->logLastPrepRef[tsltMbyte] & 65535; + if ((ToldTailFileNo != sltLogPartPtr.p->logTailFileNo) || + (ToldTailMByte != sltLogPartPtr.p->logTailMbyte)) { + jam(); + if (sltLogPartPtr.p->logPartState == LogPartRecord::TAIL_PROBLEM) { + if (sltLogPartPtr.p->firstLogQueue == RNIL) { + jam(); + sltLogPartPtr.p->logPartState = LogPartRecord::IDLE; + } else { + jam(); + sltLogPartPtr.p->logPartState = LogPartRecord::ACTIVE; + }//if + }//if + }//if + } +#if 0 + infoEvent("setLogTail: Available log file %d size = %d[mbytes]+%d[words]", sltLogPartPtr.i, + remainingLogSize(sltCurrLogFilePtr, sltLogPartPtr), sltCurrLogFilePtr.p->remainingWordsInMbyte); +#endif + }//for + +}//Dblqh::setLogTail() + +/* ######################################################################### */ +/* ####### GLOBAL CHECKPOINT MODULE ####### */ +/* */ +/* ######################################################################### */ +/*---------------------------------------------------------------------------*/ +/* THIS MODULE HELPS DIH IN DISCOVERING WHEN GLOBAL CHECKPOINTS ARE */ +/* RECOVERABLE. IT HANDLES THE REQUEST GCP_SAVEREQ THAT REQUESTS LQH TO */ +/* SAVE A PARTICULAR GLOBAL CHECKPOINT TO DISK AND RESPOND WHEN COMPLETED. */ +/*---------------------------------------------------------------------------*/ +/* *************** */ +/* GCP_SAVEREQ > */ +/* *************** */ +void Dblqh::execGCP_SAVEREQ(Signal* signal) +{ + jamEntry(); + const GCPSaveReq * const saveReq = (GCPSaveReq *)&signal->theData[0]; + + if (ERROR_INSERTED(5000)) { + systemErrorLab(signal); + } + + if (ERROR_INSERTED(5007)){ + CLEAR_ERROR_INSERT_VALUE; + sendSignalWithDelay(cownref, GSN_GCP_SAVEREQ, signal, 10000, + signal->length()); + return; + } + + const Uint32 dihBlockRef = saveReq->dihBlockRef; + const Uint32 dihPtr = saveReq->dihPtr; + const Uint32 gci = saveReq->gci; + + ndbrequire(gci >= cnewestCompletedGci); + + if (gci == cnewestCompletedGci) { +/*---------------------------------------------------------------------------*/ +/* GLOBAL CHECKPOINT HAVE ALREADY BEEN HANDLED. REQUEST MUST HAVE BEEN SENT */ +/* FROM NEW MASTER DIH. */ +/*---------------------------------------------------------------------------*/ + if (ccurrentGcprec == RNIL) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS INDICATES THAT WE HAVE ALREADY SENT GCP_SAVECONF TO PREVIOUS MASTER. */ +/* WE SIMPLY SEND IT ALSO TO THE NEW MASTER. */ +/*---------------------------------------------------------------------------*/ + GCPSaveConf * const saveConf = (GCPSaveConf*)&signal->theData[0]; + saveConf->dihPtr = dihPtr; + saveConf->nodeId = getOwnNodeId(); + saveConf->gci = cnewestCompletedGci; + sendSignal(dihBlockRef, GSN_GCP_SAVECONF, signal, + GCPSaveConf::SignalLength, JBA); + return; + } + jam(); +/*---------------------------------------------------------------------------*/ +/* WE HAVE NOT YET SENT THE RESPONSE TO THE OLD MASTER. WE WILL SET THE NEW */ +/* RECEIVER OF THE RESPONSE AND THEN EXIT SINCE THE PROCESS IS ALREADY */ +/* STARTED. */ +/*---------------------------------------------------------------------------*/ + gcpPtr.i = ccurrentGcprec; + ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); + gcpPtr.p->gcpUserptr = dihPtr; + gcpPtr.p->gcpBlockref = dihBlockRef; + return; + }//if + + ndbrequire(ccurrentGcprec == RNIL); + + + if(getNodeState().startLevel >= NodeState::SL_STOPPING_4){ + GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0]; + saveRef->dihPtr = dihPtr; + saveRef->nodeId = getOwnNodeId(); + saveRef->gci = gci; + saveRef->errorCode = GCPSaveRef::NodeShutdownInProgress; + sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal, + GCPSaveRef::SignalLength, JBB); + return; + } + + if(getNodeState().getNodeRestartInProgress()){ + GCPSaveRef * const saveRef = (GCPSaveRef*)&signal->theData[0]; + saveRef->dihPtr = dihPtr; + saveRef->nodeId = getOwnNodeId(); + saveRef->gci = gci; + saveRef->errorCode = GCPSaveRef::NodeRestartInProgress; + sendSignal(dihBlockRef, GSN_GCP_SAVEREF, signal, + GCPSaveRef::SignalLength, JBB); + return; + } + + ccurrentGcprec = 0; + gcpPtr.i = ccurrentGcprec; + ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); + + cnewestCompletedGci = gci; + if (gci > cnewestGci) { + jam(); + cnewestGci = gci; + }//if + + gcpPtr.p->gcpBlockref = dihBlockRef; + gcpPtr.p->gcpUserptr = dihPtr; + gcpPtr.p->gcpId = gci; + bool tlogActive = false; + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + ptrAss(logPartPtr, logPartRecord); + if (logPartPtr.p->logPartState == LogPartRecord::ACTIVE) { + jam(); + logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_TRUE; + tlogActive = true; + } else { + jam(); + logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + writeCompletedGciLog(signal); + }//if + }//for + if (tlogActive == true) { + jam(); + return; + }//if + initGcpRecLab(signal); + startTimeSupervision(signal); + return; +}//Dblqh::execGCP_SAVEREQ() + +/* ------------------------------------------------------------------------- */ +/* START TIME SUPERVISION OF THE LOG PARTS. */ +/* ------------------------------------------------------------------------- */ +void Dblqh::startTimeSupervision(Signal* signal) +{ + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +/* WE HAVE TO START CHECKING IF THE LOG IS TO BE WRITTEN EVEN IF PAGES ARE */ +/* FULL. INITIALISE THE VALUES OF WHERE WE ARE IN THE LOG CURRENTLY. */ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + logPartPtr.p->logPartTimer = 0; + logPartPtr.p->logTimer = 1; + signal->theData[0] = ZTIME_SUPERVISION; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//for +}//Dblqh::startTimeSupervision() + +/*---------------------------------------------------------------------------*/ +/* WE SET THE GLOBAL CHECKPOINT VARIABLES AFTER WRITING THE COMPLETED GCI LOG*/ +/* RECORD. THIS ENSURES THAT WE WILL ENCOUNTER THE COMPLETED GCI RECORD WHEN */ +/* WE EXECUTE THE FRAGMENT LOG. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::initGcpRecLab(Signal* signal) +{ +/* ======================================================================== */ +/* ======= INITIATE GCP RECORD ======= */ +/* */ +/* SUBROUTINE SHORT NAME = IGR */ +/* ======================================================================== */ + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); +/*--------------------------------------------------*/ +/* BY SETTING THE GCPREC = 0 WE START THE */ +/* CHECKING BY CHECK_GCP_COMPLETED. THIS */ +/* CHECKING MUST NOT BE STARTED UNTIL WE HAVE */ +/* INSERTED ALL COMPLETE GCI LOG RECORDS IN */ +/* ALL LOG PARTS. */ +/*--------------------------------------------------*/ + logPartPtr.p->gcprec = 0; + gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZWAIT_DISK; + gcpPtr.p->gcpSyncReady[logPartPtr.i] = ZFALSE; + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + gcpPtr.p->gcpFilePtr[logPartPtr.i] = logFilePtr.i; + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + if (logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == ZPAGE_HEADER_SIZE) { + jam(); +/*--------------------------------------------------*/ +/* SINCE THE CURRENT FILEPAGE POINTS AT THE */ +/* NEXT WORD TO BE WRITTEN WE HAVE TO ADJUST */ +/* FOR THIS BY DECREASING THE FILE PAGE BY ONE*/ +/* IF NO WORD HAS BEEN WRITTEN ON THE CURRENT */ +/* FILEPAGE. */ +/*--------------------------------------------------*/ + gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage - 1; + gcpPtr.p->gcpWordNo[logPartPtr.i] = ZPAGE_SIZE - 1; + } else { + jam(); + gcpPtr.p->gcpPageNo[logPartPtr.i] = logFilePtr.p->currentFilepage; + gcpPtr.p->gcpWordNo[logPartPtr.i] = + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1; + }//if + }//for + return; +}//Dblqh::initGcpRecLab() + +/* ========================================================================= */ +/* ==== CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED AFTER A COMPLETED===== */ +/* DISK WRITE. */ +/* */ +/* SUBROUTINE SHORT NAME = CGC */ +/* ========================================================================= */ +void Dblqh::checkGcpCompleted(Signal* signal, + Uint32 tcgcPageWritten, + Uint32 tcgcWordWritten) +{ + UintR tcgcFlag; + UintR tcgcJ; + + gcpPtr.i = logPartPtr.p->gcprec; + if (gcpPtr.i != RNIL) { + jam(); +/* ------------------------------------------------------------------------- */ +/* IF THE GLOBAL CHECKPOINT IS NOT WAITING FOR COMPLETION THEN WE CAN QUIT */ +/* THE SEARCH IMMEDIATELY. */ +/* ------------------------------------------------------------------------- */ + ptrCheckGuard(gcpPtr, cgcprecFileSize, gcpRecord); + if (gcpPtr.p->gcpFilePtr[logPartPtr.i] == logFilePtr.i) { +/* ------------------------------------------------------------------------- */ +/* IF THE COMPLETED DISK OPERATION WAS ON ANOTHER FILE THAN THE ONE WE ARE */ +/* WAITING FOR, THEN WE CAN ALSO QUIT THE SEARCH IMMEDIATELY. */ +/* ------------------------------------------------------------------------- */ + if (tcgcPageWritten < gcpPtr.p->gcpPageNo[logPartPtr.i]) { + jam(); +/* ------------------------------------------------------------------------- */ +/* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ +/* ------------------------------------------------------------------------- */ + return; + } else { + if (tcgcPageWritten == gcpPtr.p->gcpPageNo[logPartPtr.i]) { + if (tcgcWordWritten < gcpPtr.p->gcpWordNo[logPartPtr.i]) { + jam(); +/* ------------------------------------------------------------------------- */ +/* THIS LOG PART HAVE NOT YET WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ +/* ------------------------------------------------------------------------- */ + return; + }//if + }//if + }//if +/* ------------------------------------------------------------------------- */ +/* THIS LOG PART HAVE WRITTEN THE GLOBAL CHECKPOINT TO DISK. */ +/* ------------------------------------------------------------------------- */ + logPartPtr.p->gcprec = RNIL; + gcpPtr.p->gcpLogPartState[logPartPtr.i] = ZON_DISK; + tcgcFlag = ZTRUE; + for (tcgcJ = 0; tcgcJ <= 3; tcgcJ++) { + jam(); + if (gcpPtr.p->gcpLogPartState[tcgcJ] != ZON_DISK) { + jam(); +/* ------------------------------------------------------------------------- */ +/*ALL LOG PARTS HAVE NOT SAVED THIS GLOBAL CHECKPOINT TO DISK YET. WAIT FOR */ +/*THEM TO COMPLETE. */ +/* ------------------------------------------------------------------------- */ + tcgcFlag = ZFALSE; + }//if + }//for + if (tcgcFlag == ZTRUE) { + jam(); +/* ------------------------------------------------------------------------- */ +/*WE HAVE FOUND A COMPLETED GLOBAL CHECKPOINT OPERATION. WE NOW NEED TO SEND */ +/*GCP_SAVECONF, REMOVE THE GCP RECORD FROM THE LIST OF WAITING GCP RECORDS */ +/*ON THIS LOG PART AND RELEASE THE GCP RECORD. */ +// After changing the log implementation we need to perform a FSSYNCREQ on all +// log files where the last log word resided first before proceeding. +/* ------------------------------------------------------------------------- */ + UintR Ti; + for (Ti = 0; Ti < 4; Ti++) { + LogFileRecordPtr loopLogFilePtr; + loopLogFilePtr.i = gcpPtr.p->gcpFilePtr[Ti]; + ptrCheckGuard(loopLogFilePtr, clogFileFileSize, logFileRecord); + if (loopLogFilePtr.p->logFileStatus == LogFileRecord::OPEN) { + jam(); + signal->theData[0] = loopLogFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = gcpPtr.p->gcpFilePtr[Ti]; + sendSignal(NDBFS_REF, GSN_FSSYNCREQ, signal, 3, JBA); + } else { + ndbrequire((loopLogFilePtr.p->logFileStatus == + LogFileRecord::CLOSED) || + (loopLogFilePtr.p->logFileStatus == + LogFileRecord::CLOSING_WRITE_LOG) || + (loopLogFilePtr.p->logFileStatus == + LogFileRecord::OPENING_WRITE_LOG)); + signal->theData[0] = loopLogFilePtr.i; + execFSSYNCCONF(signal); + }//if + }//for + return; + }//if + }//if + }//if +}//Dblqh::checkGcpCompleted() + +void +Dblqh::execFSSYNCCONF(Signal* signal) +{ + GcpRecordPtr localGcpPtr; + LogFileRecordPtr localLogFilePtr; + LogPartRecordPtr localLogPartPtr; + localLogFilePtr.i = signal->theData[0]; + ptrCheckGuard(localLogFilePtr, clogFileFileSize, logFileRecord); + localLogPartPtr.i = localLogFilePtr.p->logPartRec; + localGcpPtr.i = ccurrentGcprec; + ptrCheckGuard(localGcpPtr, cgcprecFileSize, gcpRecord); + localGcpPtr.p->gcpSyncReady[localLogPartPtr.i] = ZTRUE; + UintR Ti; + for (Ti = 0; Ti < 4; Ti++) { + jam(); + if (localGcpPtr.p->gcpSyncReady[Ti] == ZFALSE) { + jam(); + return; + }//if + }//for + GCPSaveConf * const saveConf = (GCPSaveConf *)&signal->theData[0]; + saveConf->dihPtr = localGcpPtr.p->gcpUserptr; + saveConf->nodeId = getOwnNodeId(); + saveConf->gci = localGcpPtr.p->gcpId; + sendSignal(localGcpPtr.p->gcpBlockref, GSN_GCP_SAVECONF, signal, + GCPSaveConf::SignalLength, JBA); + ccurrentGcprec = RNIL; +}//Dblqh::execFSSYNCCONF() + +void +Dblqh::execFSSYNCREF(Signal* signal) +{ + jamEntry(); + systemErrorLab(signal); + return; +}//Dblqh::execFSSYNCREF() + + +/* ######################################################################### */ +/* ####### FILE HANDLING MODULE ####### */ +/* */ +/* ######################################################################### */ +/* THIS MODULE HANDLES RESPONSE MESSAGES FROM THE FILE SYSTEM */ +/* ######################################################################### */ +/* ######################################################################### */ +/* SIGNAL RECEPTION MODULE */ +/* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ +/* */ +/* THIS MODULE CHECKS THE STATE AND JUMPS TO THE PROPER PART OF THE FILE */ +/* HANDLING MODULE. */ +/* ######################################################################### */ +/* *************** */ +/* FSCLOSECONF > */ +/* *************** */ +void Dblqh::execFSCLOSECONF(Signal* signal) +{ + jamEntry(); + logFilePtr.i = signal->theData[0]; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + switch (logFilePtr.p->logFileStatus) { + case LogFileRecord::CLOSE_SR_INVALIDATE_PAGES: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + // Set the prev file to check if we shall close it. + logFilePtr.i = logFilePtr.p->prevLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + exitFromInvalidate(signal); + return; + break; + case LogFileRecord::CLOSING_INIT: + jam(); + closingInitLab(signal); + return; + break; + case LogFileRecord::CLOSING_SR: + jam(); + closingSrLab(signal); + return; + break; + case LogFileRecord::CLOSING_EXEC_SR: + jam(); + closeExecSrLab(signal); + return; + break; + case LogFileRecord::CLOSING_EXEC_SR_COMPLETED: + jam(); + closeExecSrCompletedLab(signal); + return; + break; + case LogFileRecord::CLOSING_WRITE_LOG: + jam(); + closeWriteLogLab(signal); + return; + break; + case LogFileRecord::CLOSING_EXEC_LOG: + jam(); + closeExecLogLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch +}//Dblqh::execFSCLOSECONF() + +/* ************>> */ +/* FSCLOSEREF > */ +/* ************>> */ +void Dblqh::execFSCLOSEREF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + systemErrorLab(signal); + return; +}//Dblqh::execFSCLOSEREF() + +/* ************>> */ +/* FSOPENCONF > */ +/* ************>> */ +void Dblqh::execFSOPENCONF(Signal* signal) +{ + jamEntry(); + initFsopenconf(signal); + switch (logFilePtr.p->logFileStatus) { + case LogFileRecord::OPEN_SR_INVALIDATE_PAGES: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + readFileInInvalidate(signal); + return; + break; + case LogFileRecord::OPENING_INIT: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openFileInitLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_FRONTPAGE: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrFrontpageLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_LAST_FILE: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrLastFileLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_NEXT_FILE: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrNextFileLab(signal); + return; + break; + case LogFileRecord::OPEN_EXEC_SR_START: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openExecSrStartLab(signal); + return; + break; + case LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openExecSrNewMbyteLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_FOURTH_PHASE: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrFourthPhaseLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_FOURTH_NEXT: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrFourthNextLab(signal); + return; + break; + case LogFileRecord::OPEN_SR_FOURTH_ZERO: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openSrFourthZeroLab(signal); + return; + break; + case LogFileRecord::OPENING_WRITE_LOG: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + return; + break; + case LogFileRecord::OPEN_EXEC_LOG: + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN; + openExecLogLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch +}//Dblqh::execFSOPENCONF() + +/* ************> */ +/* FSOPENREF > */ +/* ************> */ +void Dblqh::execFSOPENREF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + systemErrorLab(signal); + return; +}//Dblqh::execFSOPENREF() + +/* ************>> */ +/* FSREADCONF > */ +/* ************>> */ +void Dblqh::execFSREADCONF(Signal* signal) +{ + jamEntry(); + initFsrwconf(signal); + + switch (lfoPtr.p->lfoState) { + case LogFileOperationRecord::READ_SR_LAST_MBYTE: + jam(); + releaseLfo(signal); + readSrLastMbyteLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FRONTPAGE: + jam(); + releaseLfo(signal); + readSrFrontpageLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_LAST_FILE: + jam(); + releaseLfo(signal); + readSrLastFileLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_NEXT_FILE: + jam(); + releaseLfo(signal); + readSrNextFileLab(signal); + return; + break; + case LogFileOperationRecord::READ_EXEC_SR: + jam(); + readExecSrLab(signal); + return; + break; + case LogFileOperationRecord::READ_EXEC_LOG: + jam(); + readExecLogLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: + jam(); + invalidateLogAfterLastGCI(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FOURTH_PHASE: + jam(); + releaseLfo(signal); + readSrFourthPhaseLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FOURTH_ZERO: + jam(); + releaseLfo(signal); + readSrFourthZeroLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch +}//Dblqh::execFSREADCONF() + +/* ************>> */ +/* FSREADCONF > */ +/* ************>> */ +void Dblqh::execFSREADREF(Signal* signal) +{ + jamEntry(); + lfoPtr.i = signal->theData[0]; + ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + terrorCode = signal->theData[1]; + switch (lfoPtr.p->lfoState) { + case LogFileOperationRecord::READ_SR_LAST_MBYTE: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FRONTPAGE: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_LAST_FILE: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_NEXT_FILE: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_EXEC_SR: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_EXEC_LOG: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FOURTH_PHASE: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_FOURTH_ZERO: + jam(); + systemErrorLab(signal); + return; + break; + case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: + jam() + systemErrorLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + return; +}//Dblqh::execFSREADREF() + +/* *************** */ +/* FSWRITECONF > */ +/* *************** */ +void Dblqh::execFSWRITECONF(Signal* signal) +{ + jamEntry(); + initFsrwconf(signal); + switch (lfoPtr.p->lfoState) { + case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: + jam(); + invalidateLogAfterLastGCI(signal); + return; + break; + case LogFileOperationRecord::WRITE_PAGE_ZERO: + jam(); + writePageZeroLab(signal); + return; + break; + case LogFileOperationRecord::LAST_WRITE_IN_FILE: + jam(); + lastWriteInFileLab(signal); + return; + break; + case LogFileOperationRecord::INIT_WRITE_AT_END: + jam(); + initWriteEndLab(signal); + return; + break; + case LogFileOperationRecord::INIT_FIRST_PAGE: + jam(); + initFirstPageLab(signal); + return; + break; + case LogFileOperationRecord::WRITE_GCI_ZERO: + jam(); + writeGciZeroLab(signal); + return; + break; + case LogFileOperationRecord::WRITE_DIRTY: + jam(); + writeDirtyLab(signal); + return; + break; + case LogFileOperationRecord::WRITE_INIT_MBYTE: + jam(); + writeInitMbyteLab(signal); + return; + break; + case LogFileOperationRecord::ACTIVE_WRITE_LOG: + jam(); + writeLogfileLab(signal); + return; + break; + case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: + jam(); + firstPageWriteLab(signal); + return; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch +}//Dblqh::execFSWRITECONF() + +/* ************>> */ +/* FSWRITEREF > */ +/* ************>> */ +void Dblqh::execFSWRITEREF(Signal* signal) +{ + jamEntry(); + lfoPtr.i = signal->theData[0]; + ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + terrorCode = signal->theData[1]; + switch (lfoPtr.p->lfoState) { + case LogFileOperationRecord::WRITE_PAGE_ZERO: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::LAST_WRITE_IN_FILE: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::INIT_WRITE_AT_END: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::INIT_FIRST_PAGE: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::WRITE_GCI_ZERO: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::WRITE_DIRTY: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::WRITE_INIT_MBYTE: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::ACTIVE_WRITE_LOG: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: + jam(); + systemErrorLab(signal); + break; + case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: + jam(); + systemErrorLab(signal); + break; + default: + jam(); + systemErrorLab(signal); + break; + }//switch +}//Dblqh::execFSWRITEREF() + + +/* ========================================================================= */ +/* ======= INITIATE WHEN RECEIVING FSOPENCONF ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initFsopenconf(Signal* signal) +{ + logFilePtr.i = signal->theData[0]; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logFilePtr.p->fileRef = signal->theData[1]; + logPartPtr.i = logFilePtr.p->logPartRec; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.p->currentMbyte = 0; + logFilePtr.p->filePosition = 0; + logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; +}//Dblqh::initFsopenconf() + +/* ========================================================================= */ +/* ======= INITIATE WHEN RECEIVING FSREADCONF AND FSWRITECONF ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initFsrwconf(Signal* signal) +{ + lfoPtr.i = signal->theData[0]; + ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + logFilePtr.i = lfoPtr.p->logFileRec; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPartPtr.i = logFilePtr.p->logPartRec; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logPagePtr.i = lfoPtr.p->firstLfoPage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); +}//Dblqh::initFsrwconf() + +/* ######################################################################### */ +/* NORMAL OPERATION MODULE */ +/* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ +/* */ +/* THIS PART HANDLES THE NORMAL OPENING, CLOSING AND WRITING OF LOG FILES */ +/* DURING NORMAL OPERATION. */ +/* ######################################################################### */ +/*---------------------------------------------------------------------------*/ +/* THIS SIGNAL IS USED TO SUPERVISE THAT THE LOG RECORDS ARE NOT KEPT IN MAIN*/ +/* MEMORY FOR MORE THAN 1 SECOND TO ACHIEVE THE PROPER RELIABILITY. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::timeSup(Signal* signal) +{ + LogPageRecordPtr origLogPagePtr; + Uint32 wordWritten; + + jamEntry(); + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + if (logPartPtr.p->logPartTimer != logPartPtr.p->logTimer) { + jam(); +/*--------------------------------------------------------------------------*/ +/* THIS LOG PART HAS NOT WRITTEN TO DISK DURING THE LAST SECOND. */ +/*--------------------------------------------------------------------------*/ + switch (logPartPtr.p->logPartState) { + case LogPartRecord::FILE_CHANGE_PROBLEM: + jam(); +/*--------------------------------------------------------------------------*/ +/* THIS LOG PART HAS PROBLEMS IN CHANGING FILES MAKING IT IMPOSSIBLE */ +// TO WRITE TO THE FILE CURRENTLY. WE WILL COMEBACK LATER AND SEE IF +// THE PROBLEM HAS BEEN FIXED. +/*--------------------------------------------------------------------------*/ + case LogPartRecord::ACTIVE: + jam(); +/*---------------------------------------------------------------------------*/ +/* AN OPERATION IS CURRENTLY ACTIVE IN WRITING THIS LOG PART. WE THUS CANNOT */ +/* WRITE ANYTHING TO DISK AT THIS MOMENT. WE WILL SEND A SIGNAL DELAYED FOR */ +/* 10 MS AND THEN TRY AGAIN. POSSIBLY THE LOG PART WILL HAVE BEEN WRITTEN */ +/* UNTIL THEN OR ELSE IT SHOULD BE FREE TO WRITE AGAIN. */ +/*---------------------------------------------------------------------------*/ + signal->theData[0] = ZTIME_SUPERVISION; + signal->theData[1] = logPartPtr.i; + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 10, 2); + return; + break; + case LogPartRecord::IDLE: + case LogPartRecord::TAIL_PROBLEM: + jam(); +/*---------------------------------------------------------------------------*/ +/* IDLE AND NOT WRITTEN TO DISK IN A SECOND. ALSO WHEN WE HAVE A TAIL PROBLEM*/ +/* WE HAVE TO WRITE TO DISK AT TIMES. WE WILL FIRST CHECK WHETHER ANYTHING */ +/* AT ALL HAVE BEEN WRITTEN TO THE PAGES BEFORE WRITING TO DISK. */ +/*---------------------------------------------------------------------------*/ +/* WE HAVE TO WRITE TO DISK IN ALL CASES SINCE THERE COULD BE INFORMATION */ +/* STILL IN THE LOG THAT WAS GENERATED BEFORE THE PREVIOUS TIME SUPERVISION */ +/* BUT AFTER THE LAST DISK WRITE. THIS PREVIOUSLY STOPPED ALL DISK WRITES */ +/* WHEN NO MORE LOG WRITES WERE PERFORMED (THIS HAPPENED WHEN LOG GOT FULL */ +/* AND AFTER LOADING THE INITIAL RECORDS IN INITIAL START). */ +/*---------------------------------------------------------------------------*/ + if (((logFilePtr.p->currentFilepage + 1) & (ZPAGES_IN_MBYTE -1)) == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS IS THE LAST PAGE IN THIS MBYTE. WRITE NEXT LOG AND SWITCH TO NEXT */ +/* MBYTE. */ +/*---------------------------------------------------------------------------*/ + changeMbyte(signal); + } else { +/*---------------------------------------------------------------------------*/ +/* WRITE THE LOG PAGE TO DISK EVEN IF IT IS NOT FULL. KEEP PAGE AND WRITE A */ +/* COPY. THE ORIGINAL PAGE WILL BE WRITTEN AGAIN LATER ON. */ +/*---------------------------------------------------------------------------*/ + wordWritten = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] - 1; + origLogPagePtr.i = logPagePtr.i; + origLogPagePtr.p = logPagePtr.p; + seizeLogpage(signal); + MEMCOPY_NO_WORDS(&logPagePtr.p->logPageWord[0], + &origLogPagePtr.p->logPageWord[0], + wordWritten + 1); + ndbrequire(wordWritten < ZPAGE_SIZE); + if (logFilePtr.p->noLogpagesInBuffer > 0) { + jam(); + completedLogPage(signal, ZENFORCE_WRITE); +/*---------------------------------------------------------------------------*/ +/*SINCE WE ARE ONLY WRITING PART OF THE LAST PAGE WE HAVE TO UPDATE THE WORD */ +/*WRITTEN TO REFLECT THE REAL LAST WORD WRITTEN. WE ALSO HAVE TO MOVE THE */ +/*FILE POSITION ONE STEP BACKWARDS SINCE WE ARE NOT WRITING THE LAST PAGE */ +/*COMPLETELY. IT WILL BE WRITTEN AGAIN. */ +/*---------------------------------------------------------------------------*/ + lfoPtr.p->lfoWordWritten = wordWritten; + logFilePtr.p->filePosition = logFilePtr.p->filePosition - 1; + } else { + if (wordWritten == (ZPAGE_HEADER_SIZE - 1)) { +/*---------------------------------------------------------------------------*/ +/*THIS IS POSSIBLE BUT VERY UNLIKELY. IF THE PAGE WAS COMPLETED AFTER THE LAST*/ +/*WRITE TO DISK THEN NO_LOG_PAGES_IN_BUFFER > 0 AND IF NOT WRITTEN SINCE LAST*/ +/*WRITE TO DISK THEN THE PREVIOUS PAGE MUST HAVE BEEN WRITTEN BY SOME */ +/*OPERATION AND THAT BECAME COMPLETELY FULL. IN ANY CASE WE NEED NOT WRITE AN*/ +/*EMPTY PAGE TO DISK. */ +/*---------------------------------------------------------------------------*/ + jam(); + releaseLogpage(signal); + } else { + jam(); + writeSinglePage(signal, logFilePtr.p->currentFilepage, wordWritten); + lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; + }//if + }//if + }//if + break; + default: + ndbrequire(false); + break; + }//switch + }//if + logPartPtr.p->logTimer++; + return; +}//Dblqh::timeSup() + +void Dblqh::writeLogfileLab(Signal* signal) +{ +/*---------------------------------------------------------------------------*/ +/* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK */ +/* WRITE. */ +/*---------------------------------------------------------------------------*/ + switch (logFilePtr.p->fileChangeState) { + case LogFileRecord::NOT_ONGOING: + jam(); + checkGcpCompleted(signal, + ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1), + lfoPtr.p->lfoWordWritten); + break; +#if 0 + case LogFileRecord::BOTH_WRITES_ONGOING: + jam(); + ndbout_c("not crashing!!"); + // Fall-through +#endif + case LogFileRecord::WRITE_PAGE_ZERO_ONGOING: + case LogFileRecord::LAST_WRITE_ONGOING: + jam(); + logFilePtr.p->lastPageWritten = (lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1; + logFilePtr.p->lastWordWritten = lfoPtr.p->lfoWordWritten; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + releaseLfoPages(signal); + releaseLfo(signal); + return; +}//Dblqh::writeLogfileLab() + +void Dblqh::closeWriteLogLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + return; +}//Dblqh::closeWriteLogLab() + +/* ######################################################################### */ +/* FILE CHANGE MODULE */ +/* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ +/* */ +/*THIS PART OF THE FILE MODULE HANDLES WHEN WE ARE CHANGING LOG FILE DURING */ +/*NORMAL OPERATION. WE HAVE TO BE CAREFUL WHEN WE ARE CHANGING LOG FILE SO */ +/*THAT WE DO NOT COMPLICATE THE SYSTEM RESTART PROCESS TOO MUCH. */ +/*THE IDEA IS THAT WE START BY WRITING THE LAST WRITE IN THE OLD FILE AND WE */ +/*ALSO WRITE THE FIRST PAGE OF THE NEW FILE CONCURRENT WITH THAT. THIS FIRST */ +/*PAGE IN THE NEW FILE DO NOT CONTAIN ANY LOG RECORDS OTHER THAN A DESCRIPTOR*/ +/*CONTAINING INFORMATION ABOUT GCI'S NEEDED AT SYSTEM RESTART AND A NEXT LOG */ +/*RECORD. */ +/* */ +/*WHEN BOTH OF THOSE WRITES HAVE COMPLETED WE ALSO WRITE PAGE ZERO IN FILE */ +/*ZERO. THE ONLY INFORMATION WHICH IS INTERESTING HERE IS THE NEW FILE NUMBER*/ +/* */ +/*IF OPTIMISATIONS ARE NEEDED OF THE LOG HANDLING THEN IT IS POSSIBLE TO */ +/*AVOID WRITING THE FIRST PAGE OF THE NEW PAGE IMMEDIATELY. THIS COMPLICATES */ +/*THE SYSTEM RESTART AND ONE HAS TO TAKE SPECIAL CARE WITH FILE ZERO. IT IS */ +/*HOWEVER NO LARGE PROBLEM TO CHANGE INTO THIS SCENARIO. TO AVOID ALSO THE */ +/*WRITING OF PAGE ZERO IS ALSO POSSIBLE BUT COMPLICATES THE DESIGN EVEN */ +/*FURTHER. IT GETS FAIRLY COMPLEX TO FIND THE END OF THE LOG. SOME SORT OF */ +/*BINARY SEARCH IS HOWEVER MOST LIKELY A GOOD METHODOLOGY FOR THIS. */ +/* ######################################################################### */ +void Dblqh::firstPageWriteLab(Signal* signal) +{ + releaseLfo(signal); +/*---------------------------------------------------------------------------*/ +/* RELEASE PAGE ZERO IF THE FILE IS NOT FILE 0. */ +/*---------------------------------------------------------------------------*/ + Uint32 fileNo = logFilePtr.p->fileNo; + if (fileNo != 0) { + jam(); + releaseLogpage(signal); + }//if +/*---------------------------------------------------------------------------*/ +/* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN */ +/* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE */ +/* LAST FILE WHERE LOGGING HAS STARTED. */ +/*---------------------------------------------------------------------------*/ +/* FIRST CHECK WHETHER THE LAST WRITE IN THE PREVIOUS FILE HAVE COMPLETED */ +/*---------------------------------------------------------------------------*/ + if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE LAST WRITE WAS STILL ONGOING. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::LAST_WRITE_ONGOING; + return; + } else { + jam(); + ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::FIRST_WRITE_ONGOING); +/*---------------------------------------------------------------------------*/ +/* WRITE TO PAGE 0 IN IN FILE 0 NOW. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING; + if (fileNo == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; + return; + } else { + jam(); +/*---------------------------------------------------------------------------*/ +/* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE */ +/* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS */ +/* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE. */ +/* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE */ +/* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE */ +/* LOG PART. */ +/*---------------------------------------------------------------------------*/ + Uint32 currLogFile = logFilePtr.i; + logFilePtr.i = logPartPtr.p->firstLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->logPageZero; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; + writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + lfoPtr.p->logFileRec = currLogFile; + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; + return; + }//if + }//if +}//Dblqh::firstPageWriteLab() + +void Dblqh::lastWriteInFileLab(Signal* signal) +{ + LogFileRecordPtr locLogFilePtr; +/*---------------------------------------------------------------------------*/ +/* CHECK IF ANY GLOBAL CHECKPOINTS ARE COMPLETED DUE TO THIS COMPLETED DISK */ +/* WRITE. */ +/*---------------------------------------------------------------------------*/ + checkGcpCompleted(signal, + ((lfoPtr.p->lfoPageNo + lfoPtr.p->noPagesRw) - 1), + (ZPAGE_SIZE - 1)); + releaseLfoPages(signal); + releaseLfo(signal); +/*---------------------------------------------------------------------------*/ +/* IF THE FILE IS NOT IN USE OR THE NEXT FILE TO BE USED WE WILL CLOSE IT. */ +/*---------------------------------------------------------------------------*/ + locLogFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + if (logFilePtr.i != locLogFilePtr.i) { + if (logFilePtr.i != locLogFilePtr.p->nextLogFile) { + if (logFilePtr.p->fileNo != 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE FILE IS NOT FILE ZERO EITHER. WE WILL NOT CLOSE FILE ZERO SINCE WE */ +/* USE IT TO KEEP TRACK OF THE CURRENT LOG FILE BY WRITING PAGE ZERO IN */ +/* FILE ZERO. */ +/*---------------------------------------------------------------------------*/ +/* WE WILL CLOSE THE FILE. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_WRITE_LOG; + closeFile(signal, logFilePtr); + }//if + }//if + }//if +/*---------------------------------------------------------------------------*/ +/* IF A NEW FILE HAS BEEN OPENED WE SHALL ALWAYS ALSO WRITE TO PAGE O IN */ +/* FILE 0. THE AIM IS TO MAKE RESTARTS EASIER BY SPECIFYING WHICH IS THE */ +/* LAST FILE WHERE LOGGING HAS STARTED. */ +/*---------------------------------------------------------------------------*/ +/* FIRST CHECK WHETHER THE FIRST WRITE IN THE NEW FILE HAVE COMPLETED */ +/* THIS STATE INFORMATION IS IN THE NEW LOG FILE AND THUS WE HAVE TO MOVE */ +/* THE LOG FILE POINTER TO THIS LOG FILE. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + if (logFilePtr.p->fileChangeState == LogFileRecord::BOTH_WRITES_ONGOING) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE FIRST WRITE WAS STILL ONGOING. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::FIRST_WRITE_ONGOING; + return; + } else { + ndbrequire(logFilePtr.p->fileChangeState == LogFileRecord::LAST_WRITE_ONGOING); +/*---------------------------------------------------------------------------*/ +/* WRITE TO PAGE 0 IN IN FILE 0 NOW. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::WRITE_PAGE_ZERO_ONGOING; + Uint32 fileNo = logFilePtr.p->fileNo; + if (fileNo == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* IF THE NEW FILE WAS 0 THEN WE HAVE ALREADY WRITTEN PAGE ZERO IN FILE 0. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; + return; + } else { + jam(); +/*---------------------------------------------------------------------------*/ +/* WRITE PAGE ZERO IN FILE ZERO. LOG_FILE_REC WILL REFER TO THE LOG FILE WE */ +/* HAVE JUST WRITTEN PAGE ZERO IN TO GET HOLD OF LOG_FILE_PTR FOR THIS */ +/* RECORD QUICKLY. THIS IS NEEDED TO GET HOLD OF THE FILE_CHANGE_STATE. */ +/* THE ONLY INFORMATION WE WANT TO CHANGE IS THE LAST FILE NUMBER IN THE */ +/* FILE DESCRIPTOR. THIS IS USED AT SYSTEM RESTART TO FIND THE END OF THE */ +/* LOG PART. */ +/*---------------------------------------------------------------------------*/ + Uint32 currLogFile = logFilePtr.i; + logFilePtr.i = logPartPtr.p->firstLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->logPageZero; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; + writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + lfoPtr.p->logFileRec = currLogFile; + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; + return; + }//if + }//if +}//Dblqh::lastWriteInFileLab() + +void Dblqh::writePageZeroLab(Signal* signal) +{ + logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; +/*---------------------------------------------------------------------------*/ +/* IT COULD HAVE ARRIVED PAGE WRITES TO THE CURRENT FILE WHILE WE WERE */ +/* WAITING FOR THIS DISK WRITE TO COMPLETE. THEY COULD NOT CHECK FOR */ +/* COMPLETED GLOBAL CHECKPOINTS. THUS WE SHOULD DO THAT NOW INSTEAD. */ +/*---------------------------------------------------------------------------*/ + checkGcpCompleted(signal, + logFilePtr.p->lastPageWritten, + logFilePtr.p->lastWordWritten); + releaseLfo(signal); + return; +}//Dblqh::writePageZeroLab() + +/* ######################################################################### */ +/* INITIAL START MODULE */ +/* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ +/* */ +/*THIS MODULE INITIALISES ALL THE LOG FILES THAT ARE NEEDED AT A SYSTEM */ +/*RESTART AND WHICH ARE USED DURING NORMAL OPERATIONS. IT CREATES THE FILES */ +/*AND SETS A PROPER SIZE OF THEM AND INITIALISES THE FIRST PAGE IN EACH FILE */ +/* ######################################################################### */ +void Dblqh::openFileInitLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::OPEN_INIT; + seizeLogpage(signal); + writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, ZPAGE_SIZE - 1); + lfoPtr.p->lfoState = LogFileOperationRecord::INIT_WRITE_AT_END; + return; +}//Dblqh::openFileInitLab() + +void Dblqh::initWriteEndLab(Signal* signal) +{ + releaseLfo(signal); + initLogpage(signal); + if (logFilePtr.p->fileNo == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* PAGE ZERO IN FILE ZERO MUST SET LOG LAP TO ONE SINCE IT HAS STARTED */ +/* WRITING TO THE LOG, ALSO GLOBAL CHECKPOINTS ARE SET TO ZERO. */ +/*---------------------------------------------------------------------------*/ + logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = 0; + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] = 0; + logFilePtr.p->logMaxGciStarted[0] = 0; + logFilePtr.p->logMaxGciCompleted[0] = 0; + }//if +/*---------------------------------------------------------------------------*/ +/* REUSE CODE FOR INITIALISATION OF FIRST PAGE IN ALL LOG FILES. */ +/*---------------------------------------------------------------------------*/ + writeFileHeaderOpen(signal, ZINIT); + return; +}//Dblqh::initWriteEndLab() + +void Dblqh::initFirstPageLab(Signal* signal) +{ + releaseLfo(signal); + if (logFilePtr.p->fileNo == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/* IN FILE ZERO WE WILL INSERT A PAGE ONE WHERE WE WILL INSERT A COMPLETED */ +/* GCI RECORD FOR GCI = 0. */ +/*---------------------------------------------------------------------------*/ + initLogpage(signal); + logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE] = ZCOMPLETED_GCI_TYPE; + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + 1] = 1; + writeSinglePage(signal, 1, ZPAGE_SIZE - 1); + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_GCI_ZERO; + return; + }//if + logFilePtr.p->currentMbyte = 1; + writeInitMbyte(signal); + return; +}//Dblqh::initFirstPageLab() + +void Dblqh::writeGciZeroLab(Signal* signal) +{ + releaseLfo(signal); + logFilePtr.p->currentMbyte = 1; + writeInitMbyte(signal); + return; +}//Dblqh::writeGciZeroLab() + +void Dblqh::writeInitMbyteLab(Signal* signal) +{ + releaseLfo(signal); + logFilePtr.p->currentMbyte = logFilePtr.p->currentMbyte + 1; + if (logFilePtr.p->currentMbyte == ZNO_MBYTES_IN_FILE) { + jam(); + releaseLogpage(signal); + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_INIT; + closeFile(signal, logFilePtr); + return; + }//if + writeInitMbyte(signal); + return; +}//Dblqh::writeInitMbyteLab() + +void Dblqh::closingInitLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + logPartPtr.i = logFilePtr.p->logPartRec; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + if (logFilePtr.p->nextLogFile == logPartPtr.p->firstLogfile) { + jam(); + checkInitCompletedLab(signal); + return; + } else { + jam(); + logFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + openLogfileInit(signal); + }//if + return; +}//Dblqh::closingInitLab() + +void Dblqh::checkInitCompletedLab(Signal* signal) +{ + logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED; +/*---------------------------------------------------------------------------*/ +/* WE HAVE NOW INITIALISED ALL FILES IN THIS LOG PART. WE CAN NOW SET THE */ +/* THE LOG LAP TO ONE SINCE WE WILL START WITH LOG LAP ONE. LOG LAP = ZERO */ +/* MEANS THIS PART OF THE LOG IS NOT WRITTEN YET. */ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->logLap = 1; + logPartPtr.i = 0; +CHECK_LOG_PARTS_LOOP: + ptrAss(logPartPtr, logPartRecord); + if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS PART HAS STILL NOT COMPLETED. WAIT FOR THIS TO OCCUR. */ +/*---------------------------------------------------------------------------*/ + return; + }//if + if (logPartPtr.i == 3) { + jam(); +/*---------------------------------------------------------------------------*/ +/* ALL LOG PARTS ARE COMPLETED. NOW WE CAN CONTINUE WITH THE RESTART */ +/* PROCESSING. THE NEXT STEP IS TO PREPARE FOR EXECUTING OPERATIONS. THUS WE */ +/* NEED TO INITIALISE ALL NEEDED DATA AND TO OPEN FILE ZERO AND THE NEXT AND */ +/* TO SET THE CURRENT LOG PAGE TO BE PAGE 1 IN FILE ZERO. */ +/*---------------------------------------------------------------------------*/ + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + ptrAss(logPartPtr, logPartRecord); + signal->theData[0] = ZINIT_FOURTH; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//for + return; + } else { + jam(); + logPartPtr.i = logPartPtr.i + 1; + goto CHECK_LOG_PARTS_LOOP; + }//if +}//Dblqh::checkInitCompletedLab() + +/* ========================================================================= */ +/* ======= INITIATE LOG FILE OPERATION RECORD WHEN ALLOCATED ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initLfo(Signal* signal) +{ + lfoPtr.p->firstLfoPage = RNIL; + lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; + lfoPtr.p->logFileRec = logFilePtr.i; + lfoPtr.p->noPagesRw = 0; + lfoPtr.p->lfoPageNo = ZNIL; +}//Dblqh::initLfo() + +/* ========================================================================= */ +/* ======= INITIATE LOG FILE WHEN ALLOCATED ======= */ +/* */ +/* INPUT: TFILE_NO NUMBER OF THE FILE INITIATED */ +/* LOG_PART_PTR NUMBER OF LOG PART */ +/* SUBROUTINE SHORT NAME = IL */ +/* ========================================================================= */ +void Dblqh::initLogfile(Signal* signal, Uint32 fileNo) +{ + UintR tilTmp; + UintR tilIndex; + + logFilePtr.p->currentFilepage = 0; + logFilePtr.p->currentLogpage = RNIL; + logFilePtr.p->fileName[0] = (UintR)-1; + logFilePtr.p->fileName[1] = (UintR)-1; /* = H'FFFFFFFF = -1 */ + logFilePtr.p->fileName[2] = fileNo; /* Sfile_no */ + tilTmp = 1; /* VERSION 1 OF FILE NAME */ + tilTmp = (tilTmp << 8) + 1; /* FRAGMENT LOG => .FRAGLOG AS EXTENSION */ + tilTmp = (tilTmp << 8) + (8 + logPartPtr.i); /* DIRECTORY = D(8+Part)/DBLQH */ + tilTmp = (tilTmp << 8) + 255; /* IGNORE Pxx PART OF FILE NAME */ + logFilePtr.p->fileName[3] = tilTmp; +/* ========================================================================= */ +/* FILE NAME BECOMES /D2/DBLQH/Tpart_no/Sfile_no.FRAGLOG */ +/* ========================================================================= */ + logFilePtr.p->fileNo = fileNo; + logFilePtr.p->filePosition = 0; + logFilePtr.p->firstLfo = RNIL; + logFilePtr.p->lastLfo = RNIL; + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + logFilePtr.p->logPartRec = logPartPtr.i; + logFilePtr.p->noLogpagesInBuffer = 0; + logFilePtr.p->firstFilledPage = RNIL; + logFilePtr.p->lastFilledPage = RNIL; + logFilePtr.p->lastPageWritten = 0; + logFilePtr.p->logPageZero = RNIL; + logFilePtr.p->currentMbyte = 0; + for (tilIndex = 0; tilIndex <= 15; tilIndex++) { + logFilePtr.p->logMaxGciCompleted[tilIndex] = (UintR)-1; + logFilePtr.p->logMaxGciStarted[tilIndex] = (UintR)-1; + logFilePtr.p->logLastPrepRef[tilIndex] = 0; + }//for +}//Dblqh::initLogfile() + +/* ========================================================================= */ +/* ======= INITIATE LOG PAGE WHEN ALLOCATED ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initLogpage(Signal* signal) +{ + TcConnectionrecPtr ilpTcConnectptr; + + logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = logPartPtr.p->logLap; + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED] = + logPartPtr.p->logPartNewestCompletedGCI; + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED] = cnewestGci; + logPagePtr.p->logPageWord[ZPOS_VERSION] = NDB_VERSION; + logPagePtr.p->logPageWord[ZPOS_NO_LOG_FILES] = logPartPtr.p->noLogFiles; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; + ilpTcConnectptr.i = logPartPtr.p->firstLogTcrec; + if (ilpTcConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(ilpTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] = + (ilpTcConnectptr.p->logStartFileNo << 16) + + (ilpTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE); + } else { + jam(); + logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF] = + (logFilePtr.p->fileNo << 16) + + (logFilePtr.p->currentFilepage >> ZTWOLOG_NO_PAGES_IN_MBYTE); + }//if +}//Dblqh::initLogpage() + +/* ------------------------------------------------------------------------- */ +/* ------- OPEN LOG FILE FOR READ AND WRITE ------- */ +/* */ +/* SUBROUTINE SHORT NAME = OFR */ +/* ------------------------------------------------------------------------- */ +void Dblqh::openFileRw(Signal* signal, LogFileRecordPtr olfLogFilePtr) +{ + signal->theData[0] = cownref; + signal->theData[1] = olfLogFilePtr.i; + signal->theData[2] = olfLogFilePtr.p->fileName[0]; + signal->theData[3] = olfLogFilePtr.p->fileName[1]; + signal->theData[4] = olfLogFilePtr.p->fileName[2]; + signal->theData[5] = olfLogFilePtr.p->fileName[3]; + signal->theData[6] = ZOPEN_READ_WRITE; + sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); +}//Dblqh::openFileRw() + +/* ------------------------------------------------------------------------- */ +/* ------- OPEN LOG FILE DURING INITIAL START ------- */ +/* */ +/* SUBROUTINE SHORT NAME = OLI */ +/* ------------------------------------------------------------------------- */ +void Dblqh::openLogfileInit(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::OPENING_INIT; + signal->theData[0] = cownref; + signal->theData[1] = logFilePtr.i; + signal->theData[2] = logFilePtr.p->fileName[0]; + signal->theData[3] = logFilePtr.p->fileName[1]; + signal->theData[4] = logFilePtr.p->fileName[2]; + signal->theData[5] = logFilePtr.p->fileName[3]; + signal->theData[6] = 0x302; + sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); +}//Dblqh::openLogfileInit() + +/* OPEN FOR READ/WRITE, DO CREATE AND DO TRUNCATE FILE */ +/* ------------------------------------------------------------------------- */ +/* ------- OPEN NEXT LOG FILE ------- */ +/* */ +/* SUBROUTINE SHORT NAME = ONL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::openNextLogfile(Signal* signal) +{ + LogFileRecordPtr onlLogFilePtr; + + if (logPartPtr.p->noLogFiles > 2) { + jam(); +/* -------------------------------------------------- */ +/* IF ONLY 1 OR 2 LOG FILES EXIST THEN THEY ARE */ +/* ALWAYS OPEN AND THUS IT IS NOT NECESSARY TO */ +/* OPEN THEM NOW. */ +/* -------------------------------------------------- */ + onlLogFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(onlLogFilePtr, clogFileFileSize, logFileRecord); + if (onlLogFilePtr.p->logFileStatus != LogFileRecord::CLOSED) { + ndbrequire(onlLogFilePtr.p->fileNo == 0); + return; + }//if + onlLogFilePtr.p->logFileStatus = LogFileRecord::OPENING_WRITE_LOG; + signal->theData[0] = cownref; + signal->theData[1] = onlLogFilePtr.i; + signal->theData[2] = onlLogFilePtr.p->fileName[0]; + signal->theData[3] = onlLogFilePtr.p->fileName[1]; + signal->theData[4] = onlLogFilePtr.p->fileName[2]; + signal->theData[5] = onlLogFilePtr.p->fileName[3]; + signal->theData[6] = 2; + sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); + }//if +}//Dblqh::openNextLogfile() + + /* OPEN FOR READ/WRITE, DON'T CREATE AND DON'T TRUNCATE FILE */ +/* ------------------------------------------------------------------------- */ +/* ------- RELEASE LFO RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::releaseLfo(Signal* signal) +{ +#ifdef VM_TRACE + // Check that lfo record isn't already in free list + LogFileOperationRecordPtr TlfoPtr; + TlfoPtr.i = cfirstfreeLfo; + while (TlfoPtr.i != RNIL){ + ptrCheckGuard(TlfoPtr, clfoFileSize, logFileOperationRecord); + ndbrequire(TlfoPtr.i != lfoPtr.i); + TlfoPtr.i = TlfoPtr.p->nextLfo; + } +#endif + lfoPtr.p->nextLfo = cfirstfreeLfo; + lfoPtr.p->lfoTimer = 0; + cfirstfreeLfo = lfoPtr.i; + lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; +}//Dblqh::releaseLfo() + +/* ------------------------------------------------------------------------- */ +/* ------- RELEASE ALL LOG PAGES CONNECTED TO A LFO RECORD ------- */ +/* */ +/* SUBROUTINE SHORT NAME = RLP */ +/* ------------------------------------------------------------------------- */ +void Dblqh::releaseLfoPages(Signal* signal) +{ + LogPageRecordPtr rlpLogPagePtr; + + logPagePtr.i = lfoPtr.p->firstLfoPage; +RLP_LOOP: + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + rlpLogPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + releaseLogpage(signal); + if (rlpLogPagePtr.i != RNIL) { + jam(); + logPagePtr.i = rlpLogPagePtr.i; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + goto RLP_LOOP; + }//if + lfoPtr.p->firstLfoPage = RNIL; +}//Dblqh::releaseLfoPages() + +/* ------------------------------------------------------------------------- */ +/* ------- RELEASE LOG PAGE ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::releaseLogpage(Signal* signal) +{ +#ifdef VM_TRACE + // Check that log page isn't already in free list + LogPageRecordPtr TlogPagePtr; + TlogPagePtr.i = cfirstfreeLogPage; + while (TlogPagePtr.i != RNIL){ + ptrCheckGuard(TlogPagePtr, clogPageFileSize, logPageRecord); + ndbrequire(TlogPagePtr.i != logPagePtr.i); + TlogPagePtr.i = TlogPagePtr.p->logPageWord[ZNEXT_PAGE]; + } +#endif + + cnoOfLogPages++; + logPagePtr.p->logPageWord[ZNEXT_PAGE] = cfirstfreeLogPage; + cfirstfreeLogPage = logPagePtr.i; +}//Dblqh::releaseLogpage() + +/* ------------------------------------------------------------------------- */ +/* ------- SEIZE LFO RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::seizeLfo(Signal* signal) +{ + lfoPtr.i = cfirstfreeLfo; + ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + cfirstfreeLfo = lfoPtr.p->nextLfo; + lfoPtr.p->nextLfo = RNIL; + lfoPtr.p->lfoTimer = cLqhTimeOutCount; +}//Dblqh::seizeLfo() + +/* ------------------------------------------------------------------------- */ +/* ------- SEIZE LOG FILE RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::seizeLogfile(Signal* signal) +{ + logFilePtr.i = cfirstfreeLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); +/* ------------------------------------------------------------------------- */ +/*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_FILE_PTR = RNIL */ +/* ------------------------------------------------------------------------- */ + cfirstfreeLogFile = logFilePtr.p->nextLogFile; + logFilePtr.p->nextLogFile = RNIL; +}//Dblqh::seizeLogfile() + +/* ------------------------------------------------------------------------- */ +/* ------- SEIZE LOG PAGE RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::seizeLogpage(Signal* signal) +{ + cnoOfLogPages--; + logPagePtr.i = cfirstfreeLogPage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); +/* ------------------------------------------------------------------------- */ +/*IF LIST IS EMPTY THEN A SYSTEM CRASH IS INVOKED SINCE LOG_PAGE_PTR = RNIL */ +/* ------------------------------------------------------------------------- */ + cfirstfreeLogPage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; +}//Dblqh::seizeLogpage() + +/* ------------------------------------------------------------------------- */ +/* ------- WRITE FILE DESCRIPTOR INFORMATION ------- */ +/* */ +/* SUBROUTINE SHORT NAME: WFD */ +// Pointer handling: +// logFilePtr in +// logPartPtr in +/* ------------------------------------------------------------------------- */ +void Dblqh::writeFileDescriptor(Signal* signal) +{ + TcConnectionrecPtr wfdTcConnectptr; + UintR twfdFileNo; + UintR twfdMbyte; + +/* -------------------------------------------------- */ +/* START BY WRITING TO LOG FILE RECORD */ +/* -------------------------------------------------- */ + arrGuard(logFilePtr.p->currentMbyte, 16); + logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] = + logPartPtr.p->logPartNewestCompletedGCI; + logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] = cnewestGci; + wfdTcConnectptr.i = logPartPtr.p->firstLogTcrec; + if (wfdTcConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(wfdTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + twfdFileNo = wfdTcConnectptr.p->logStartFileNo; + twfdMbyte = wfdTcConnectptr.p->logStartPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE; + logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = + (twfdFileNo << 16) + twfdMbyte; + } else { + jam(); + logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = + (logFilePtr.p->fileNo << 16) + logFilePtr.p->currentMbyte; + }//if +}//Dblqh::writeFileDescriptor() + +/* ------------------------------------------------------------------------- */ +/* ------- WRITE THE HEADER PAGE OF A NEW FILE ------- */ +/* */ +/* SUBROUTINE SHORT NAME: WMO */ +/* ------------------------------------------------------------------------- */ +void Dblqh::writeFileHeaderOpen(Signal* signal, Uint32 wmoType) +{ + LogFileRecordPtr wmoLogFilePtr; + UintR twmoNoLogDescriptors; + UintR twmoLoop; + UintR twmoIndex; + +/* -------------------------------------------------- */ +/* WRITE HEADER INFORMATION IN THE NEW FILE. */ +/* -------------------------------------------------- */ + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_LOG_TYPE] = ZFD_TYPE; + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = + logFilePtr.p->fileNo; + if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { + jam(); + twmoNoLogDescriptors = ZMAX_LOG_FILES_IN_PAGE_ZERO; + } else { + jam(); + twmoNoLogDescriptors = logPartPtr.p->noLogFiles; + }//if + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD] = + twmoNoLogDescriptors; + wmoLogFilePtr.i = logFilePtr.i; + twmoLoop = 0; +WMO_LOOP: + jam(); + if (twmoLoop < twmoNoLogDescriptors) { + jam(); + ptrCheckGuard(wmoLogFilePtr, clogFileFileSize, logFileRecord); + for (twmoIndex = 0; twmoIndex <= ZNO_MBYTES_IN_FILE - 1; twmoIndex++) { + jam(); + arrGuard(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + twmoIndex, ZPAGE_SIZE); + logPagePtr.p->logPageWord[((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + twmoIndex] = + wmoLogFilePtr.p->logMaxGciCompleted[twmoIndex]; + arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + ZNO_MBYTES_IN_FILE) + + twmoIndex, ZPAGE_SIZE); + logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + ZNO_MBYTES_IN_FILE) + twmoIndex] = + wmoLogFilePtr.p->logMaxGciStarted[twmoIndex]; + arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + (2 * ZNO_MBYTES_IN_FILE)) + + twmoIndex, ZPAGE_SIZE); + logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (twmoLoop * ZFD_PART_SIZE)) + (2 * ZNO_MBYTES_IN_FILE)) + twmoIndex] = + wmoLogFilePtr.p->logLastPrepRef[twmoIndex]; + }//for + wmoLogFilePtr.i = wmoLogFilePtr.p->prevLogFile; + twmoLoop = twmoLoop + 1; + goto WMO_LOOP; + }//if + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = + (ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (ZFD_PART_SIZE * twmoNoLogDescriptors); + arrGuard(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX], ZPAGE_SIZE); + logPagePtr.p->logPageWord[logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]] = + ZNEXT_LOG_RECORD_TYPE; +/* ------------------------------------------------------- */ +/* THIS IS A SPECIAL WRITE OF THE FIRST PAGE IN THE */ +/* LOG FILE. THIS HAS SPECIAL SIGNIFANCE TO FIND */ +/* THE END OF THE LOG AT SYSTEM RESTART. */ +/* ------------------------------------------------------- */ + writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + if (wmoType == ZINIT) { + jam(); + lfoPtr.p->lfoState = LogFileOperationRecord::INIT_FIRST_PAGE; + } else { + jam(); + lfoPtr.p->lfoState = LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE; + }//if + logFilePtr.p->filePosition = 1; + if (wmoType == ZNORMAL) { + jam(); +/* -------------------------------------------------- */ +/* ALLOCATE A NEW PAGE SINCE THE CURRENT IS */ +/* WRITTEN. */ +/* -------------------------------------------------- */ + seizeLogpage(signal); + initLogpage(signal); + logFilePtr.p->currentLogpage = logPagePtr.i; + logFilePtr.p->currentFilepage = logFilePtr.p->currentFilepage + 1; + }//if +}//Dblqh::writeFileHeaderOpen() + +/* -------------------------------------------------- */ +/* THE NEW FILE POSITION WILL ALWAYS BE 1 SINCE */ +/* WE JUST WROTE THE FIRST PAGE IN THE LOG FILE */ +/* -------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------- WRITE A MBYTE HEADER DURING INITIAL START ------- */ +/* */ +/* SUBROUTINE SHORT NAME: WIM */ +/* ------------------------------------------------------------------------- */ +void Dblqh::writeInitMbyte(Signal* signal) +{ + initLogpage(signal); + writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, ZPAGE_SIZE - 1); + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_INIT_MBYTE; +}//Dblqh::writeInitMbyte() + +/* ------------------------------------------------------------------------- */ +/* ------- WRITE A SINGLE PAGE INTO A FILE ------- */ +/* */ +/* INPUT: TWSP_PAGE_NO THE PAGE NUMBER WRITTEN */ +/* SUBROUTINE SHORT NAME: WSP */ +/* ------------------------------------------------------------------------- */ +void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten) +{ + seizeLfo(signal); + initLfo(signal); + lfoPtr.p->firstLfoPage = logPagePtr.i; + logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + + // Calculate checksum for page + logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); + + lfoPtr.p->lfoPageNo = pageNo; + lfoPtr.p->lfoWordWritten = wordWritten; + lfoPtr.p->noPagesRw = 1; +/* -------------------------------------------------- */ +/* SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */ +/* LOG RECORD HAS BEEN SENT AT THIS TIME. */ +/* -------------------------------------------------- */ + logPartPtr.p->logPartTimer = logPartPtr.p->logTimer; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + signal->theData[3] = ZLIST_OF_PAIRS_SYNCH; + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = 1; /* ONE PAGE WRITTEN */ + signal->theData[6] = logPagePtr.i; + signal->theData[7] = pageNo; + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); +}//Dblqh::writeSinglePage() + +/* ########################################################################## + * SYSTEM RESTART PHASE ONE MODULE + * THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. + * + * THIS MODULE CONTAINS THE CODE FOR THE FIRST PHASE OF THE SYSTEM RESTART. + * THE AIM OF THIS PHASE IS TO FIND THE END OF THE LOG AND TO FIND + * INFORMATION ABOUT WHERE GLOBAL CHECKPOINTS ARE COMPLETED AND STARTED + * IN THE LOG. THIS INFORMATION IS NEEDED TO START PHASE THREE OF + * THE SYSTEM RESTART. + * ########################################################################## */ +/* -------------------------------------------------------------------------- + * A SYSTEM RESTART OR NODE RESTART IS ONGOING. WE HAVE NOW OPENED FILE 0 + * NOW WE NEED TO READ PAGE 0 TO FIND WHICH LOG FILE THAT WAS OPEN AT + * CRASH TIME. + * -------------------------------------------------------------------------- */ +void Dblqh::openSrFrontpageLab(Signal* signal) +{ + readSinglePage(signal, 0); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FRONTPAGE; + return; +}//Dblqh::openSrFrontpageLab() + +/* ------------------------------------------------------------------------- + * WE HAVE NOW READ PAGE 0 IN FILE 0. CHECK THE LAST OPEN FILE. ACTUALLY THE + * LAST OPEN FILE COULD BE THE NEXT AFTER THAT. CHECK THAT FIRST. WHEN THE + * LAST WAS FOUND WE CAN FIND ALL THE NEEDED INFORMATION WHERE TO START AND + * STOP READING THE LOG. + * -------------------------------------------------------------------------- */ +void Dblqh::readSrFrontpageLab(Signal* signal) +{ + Uint32 fileNo = logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO]; + if (fileNo == 0) { + jam(); + /* ---------------------------------------------------------------------- + * FILE 0 WAS ALSO LAST FILE SO WE DO NOT NEED TO READ IT AGAIN. + * ---------------------------------------------------------------------- */ + readSrLastFileLab(signal); + return; + }//if + /* ------------------------------------------------------------------------ + * CLOSE FILE 0 SO THAT WE HAVE CLOSED ALL FILES WHEN STARTING TO READ + * THE FRAGMENT LOG. ALSO RELEASE PAGE ZERO. + * ------------------------------------------------------------------------ */ + releaseLogpage(signal); + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; + closeFile(signal, logFilePtr); + LogFileRecordPtr locLogFilePtr; + findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_LAST_FILE; + openFileRw(signal, locLogFilePtr); + return; +}//Dblqh::readSrFrontpageLab() + +void Dblqh::openSrLastFileLab(Signal* signal) +{ + readSinglePage(signal, 0); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_FILE; + return; +}//Dblqh::openSrLastFileLab() + +void Dblqh::readSrLastFileLab(Signal* signal) +{ + logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP]; + if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { + jam(); + initGciInLogFileRec(signal, ZMAX_LOG_FILES_IN_PAGE_ZERO); + } else { + jam(); + initGciInLogFileRec(signal, logPartPtr.p->noLogFiles); + }//if + releaseLogpage(signal); + /* ------------------------------------------------------------------------ + * NOW WE HAVE FOUND THE LAST LOG FILE. WE ALSO NEED TO FIND THE LAST + * MBYTE THAT WAS LAST WRITTEN BEFORE THE SYSTEM CRASH. + * ------------------------------------------------------------------------ */ + logPartPtr.p->lastLogfile = logFilePtr.i; + readSinglePage(signal, 0); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_MBYTE; + logFilePtr.p->currentMbyte = 0; + return; +}//Dblqh::readSrLastFileLab() + +void Dblqh::readSrLastMbyteLab(Signal* signal) +{ + if (logPartPtr.p->lastMbyte == ZNIL) { + if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] < logPartPtr.p->logLap) { + jam(); + logPartPtr.p->lastMbyte = logFilePtr.p->currentMbyte - 1; + }//if + }//if + arrGuard(logFilePtr.p->currentMbyte, 16); + logFilePtr.p->logMaxGciCompleted[logFilePtr.p->currentMbyte] = + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_COMPLETED]; + logFilePtr.p->logMaxGciStarted[logFilePtr.p->currentMbyte] = + logPagePtr.p->logPageWord[ZPOS_MAX_GCI_STARTED]; + logFilePtr.p->logLastPrepRef[logFilePtr.p->currentMbyte] = + logPagePtr.p->logPageWord[ZLAST_LOG_PREP_REF]; + releaseLogpage(signal); + if (logFilePtr.p->currentMbyte < (ZNO_MBYTES_IN_FILE - 1)) { + jam(); + logFilePtr.p->currentMbyte++; + readSinglePage(signal, ZPAGES_IN_MBYTE * logFilePtr.p->currentMbyte); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_LAST_MBYTE; + return; + } else { + jam(); + /* ---------------------------------------------------------------------- + * THE LOG WAS IN THE LAST MBYTE WHEN THE CRASH OCCURRED SINCE ALL + * LOG LAPS ARE EQUAL TO THE CURRENT LOG LAP. + * ---------------------------------------------------------------------- */ + if (logPartPtr.p->lastMbyte == ZNIL) { + jam(); + logPartPtr.p->lastMbyte = ZNO_MBYTES_IN_FILE - 1; + }//if + }//if + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; + closeFile(signal, logFilePtr); + if (logPartPtr.p->noLogFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { + Uint32 fileNo; + if (logFilePtr.p->fileNo >= ZMAX_LOG_FILES_IN_PAGE_ZERO) { + jam(); + fileNo = logFilePtr.p->fileNo - ZMAX_LOG_FILES_IN_PAGE_ZERO; + } else { + jam(); + fileNo = + (logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) - + ZMAX_LOG_FILES_IN_PAGE_ZERO; + }//if + if (fileNo == 0) { + jam(); + /* -------------------------------------------------------------------- + * AVOID USING FILE 0 AGAIN SINCE THAT IS PROBABLY CLOSING AT THE + * MOMENT. + * -------------------------------------------------------------------- */ + fileNo = 1; + logPartPtr.p->srRemainingFiles = + logPartPtr.p->noLogFiles - (ZMAX_LOG_FILES_IN_PAGE_ZERO - 1); + } else { + jam(); + logPartPtr.p->srRemainingFiles = + logPartPtr.p->noLogFiles - ZMAX_LOG_FILES_IN_PAGE_ZERO; + }//if + LogFileRecordPtr locLogFilePtr; + findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE; + openFileRw(signal, locLogFilePtr); + return; + }//if + /* ------------------------------------------------------------------------ + * THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES. + * WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED. + * NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE. + * ------------------------------------------------------------------------ */ + return; +}//Dblqh::readSrLastMbyteLab() + +void Dblqh::openSrNextFileLab(Signal* signal) +{ + readSinglePage(signal, 0); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_NEXT_FILE; + return; +}//Dblqh::openSrNextFileLab() + +void Dblqh::readSrNextFileLab(Signal* signal) +{ + if (logPartPtr.p->srRemainingFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { + jam(); + initGciInLogFileRec(signal, ZMAX_LOG_FILES_IN_PAGE_ZERO); + } else { + jam(); + initGciInLogFileRec(signal, logPartPtr.p->srRemainingFiles); + }//if + releaseLogpage(signal); + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_SR; + closeFile(signal, logFilePtr); + if (logPartPtr.p->srRemainingFiles > ZMAX_LOG_FILES_IN_PAGE_ZERO) { + Uint32 fileNo; + if (logFilePtr.p->fileNo >= ZMAX_LOG_FILES_IN_PAGE_ZERO) { + jam(); + fileNo = logFilePtr.p->fileNo - ZMAX_LOG_FILES_IN_PAGE_ZERO; + } else { + jam(); + fileNo = + (logPartPtr.p->noLogFiles + logFilePtr.p->fileNo) - + ZMAX_LOG_FILES_IN_PAGE_ZERO; + }//if + if (fileNo == 0) { + jam(); + /* -------------------------------------------------------------------- + * AVOID USING FILE 0 AGAIN SINCE THAT IS PROBABLY CLOSING AT THE MOMENT. + * -------------------------------------------------------------------- */ + fileNo = 1; + logPartPtr.p->srRemainingFiles = + logPartPtr.p->srRemainingFiles - (ZMAX_LOG_FILES_IN_PAGE_ZERO - 1); + } else { + jam(); + logPartPtr.p->srRemainingFiles = + logPartPtr.p->srRemainingFiles - ZMAX_LOG_FILES_IN_PAGE_ZERO; + }//if + LogFileRecordPtr locLogFilePtr; + findLogfile(signal, fileNo, logPartPtr, &locLogFilePtr); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_NEXT_FILE; + openFileRw(signal, locLogFilePtr); + }//if + /* ------------------------------------------------------------------------ + * THERE WERE NO NEED TO READ ANY MORE PAGE ZERO IN OTHER FILES. + * WE NOW HAVE ALL THE NEEDED INFORMATION ABOUT THE GCI'S THAT WE NEED. + * NOW JUST WAIT FOR CLOSE OPERATIONS TO COMPLETE. + * ------------------------------------------------------------------------ */ + return; +}//Dblqh::readSrNextFileLab() + +void Dblqh::closingSrLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + logPartPtr.i = logFilePtr.p->logPartRec; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.i = logPartPtr.p->firstLogfile; + do { + jam(); + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + if (logFilePtr.p->logFileStatus != LogFileRecord::CLOSED) { + jam(); + /* -------------------------------------------------------------------- + * EXIT AND WAIT FOR REMAINING LOG FILES TO COMPLETE THEIR WORK. + * -------------------------------------------------------------------- */ + return; + }//if + logFilePtr.i = logFilePtr.p->nextLogFile; + } while (logFilePtr.i != logPartPtr.p->firstLogfile); + /* ------------------------------------------------------------------------ + * ALL FILES IN THIS PART HAVE BEEN CLOSED. THIS INDICATES THAT THE FIRST + * PHASE OF THE SYSTEM RESTART HAVE BEEN CONCLUDED FOR THIS LOG PART. + * CHECK IF ALL OTHER LOG PARTS ARE ALSO COMPLETED. + * ------------------------------------------------------------------------ */ + logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE_COMPLETED; + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + if (logPartPtr.p->logPartState != LogPartRecord::SR_FIRST_PHASE_COMPLETED) { + jam(); + /* -------------------------------------------------------------------- + * EXIT AND WAIT FOR THE REST OF THE LOG PARTS TO COMPLETE. + * -------------------------------------------------------------------- */ + return; + }//if + }//for + /* ------------------------------------------------------------------------ + * THE FIRST PHASE HAVE BEEN COMPLETED. + * ------------------------------------------------------------------------ */ + signal->theData[0] = ZSR_PHASE3_START; + signal->theData[1] = ZSR_PHASE1_COMPLETED; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +}//Dblqh::closingSrLab() + +/* ########################################################################## + * ####### SYSTEM RESTART PHASE TWO MODULE ####### + * + * THIS MODULE HANDLES THE SYSTEM RESTART WHERE LQH CONTROLS TUP AND ACC TO + * ENSURE THAT THEY HAVE KNOWLEDGE OF ALL FRAGMENTS AND HAVE DONE THE NEEDED + * READING OF DATA FROM FILE AND EXECUTION OF LOCAL LOGS. THIS PROCESS + * EXECUTES CONCURRENTLY WITH PHASE ONE OF THE SYSTEM RESTART. THIS PHASE + * FINDS THE INFORMATION ABOUT THE FRAGMENT LOG NEEDED TO EXECUTE THE FRAGMENT + * LOG. + * WHEN TUP AND ACC HAVE PREPARED ALL FRAGMENTS THEN LQH ORDERS THOSE LQH'S + * THAT ARE RESPONSIBLE TO EXECUTE THE FRAGMENT LOGS TO DO SO. IT IS POSSIBLE + * THAT ANOTHER NODE EXECUTES THE LOG FOR A FRAGMENT RESIDING AT THIS NODE. + * ########################################################################## */ +/* ***************>> */ +/* START_FRAGREQ > */ +/* ***************>> */ +void Dblqh::execSTART_FRAGREQ(Signal* signal) +{ + const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; + jamEntry(); + + tabptr.i = startFragReq->tableId; + Uint32 fragId = startFragReq->fragId; + + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + if (!getFragmentrec(signal, fragId)) { + startFragRefLab(signal); + return; + }//if + tabptr.p->tableStatus = Tablerec::TABLE_DEFINED; + + initFragrecSr(signal); + if (startFragReq->lcpNo == ZNIL) { + jam(); + /* ---------------------------------------------------------------------- + * THERE WAS NO LOCAL CHECKPOINT AVAILABLE FOR THIS FRAGMENT. WE DO + * NOT NEED TO READ IN THE LOCAL FRAGMENT. WE HAVE ALREADY ADDED THE + * FRAGMENT AS AN EMPTY FRAGMENT AT THIS POINT. THUS WE CAN SIMPLY + * EXIT AND THE FRAGMENT WILL PARTICIPATE IN THE EXECUTION OF THE LOG. + * PUT FRAGMENT ON LIST OF COMPLETED FRAGMENTS FOR EXECUTION OF LOG. + * ---------------------------------------------------------------------- */ + fragptr.p->nextFrag = cfirstCompletedFragSr; + cfirstCompletedFragSr = fragptr.i; + return; + }//if + if (cfirstWaitFragSr == RNIL) { + jam(); + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { + jam(); + initLcpSr(signal, startFragReq->lcpNo, + startFragReq->lcpId, tabptr.i, + fragId, fragptr.i); + signal->theData[0] = lcpPtr.i; + signal->theData[1] = cownref; + signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; + sendSignal(fragptr.p->accBlockref, GSN_SR_FRAGIDREQ, signal, 5, JBB); + return; + }//if + }//if + fragptr.p->nextFrag = cfirstWaitFragSr; + cfirstWaitFragSr = fragptr.i; +}//Dblqh::execSTART_FRAGREQ() + +void Dblqh::startFragRefLab(Signal* signal) +{ + const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; + BlockReference userRef = startFragReq->userRef; + Uint32 userPtr = startFragReq->userPtr; + signal->theData[0] = userPtr; + signal->theData[1] = terrorCode; + signal->theData[2] = cownNodeid; + sendSignal(userRef, GSN_START_FRAGREF, signal, 3, JBB); + return; +}//Dblqh::startFragRefLab() + +/* ***************>> */ +/* SR_FRAGIDCONF > */ +/* ***************>> */ +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_PTR:LCP_STATE = SR_WAIT_FRAGID + * -------------------------------------------------------------------------- */ +void Dblqh::execSR_FRAGIDCONF(Signal* signal) +{ + SrFragidConf * const srFragidConf = (SrFragidConf *)&signal->theData[0]; + jamEntry(); + + lcpPtr.i = srFragidConf->lcpPtr; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + ndbrequire(lcpPtr.p->lcpState == LcpRecord::LCP_SR_WAIT_FRAGID); + /* ------------------------------------------------------------------------ + * NO ERROR CHECKING OF TNO_LOCFRAG VALUE. OUT OF BOUND WILL IMPLY THAT AN + * INDEX OUT OF RANGE WILL CAUSE A SYSTEM RESTART WHICH IS DESIRED. + * ------------------------------------------------------------------------ */ + lcpPtr.p->lcpAccptr = srFragidConf->accPtr; + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->accFragptr[0] = srFragidConf->fragPtr[0]; + fragptr.p->accFragptr[1] = srFragidConf->fragPtr[1]; + Uint32 noLocFrag = srFragidConf->noLocFrag; + ndbrequire(noLocFrag == 2); + Uint32 fragid[2]; + Uint32 i; + for (i = 0; i < noLocFrag; i++) { + fragid[i] = srFragidConf->fragId[i]; + }//for + + for (i = 0; i < noLocFrag; i++) { + jam(); + Uint32 fragId = fragid[i]; + /* ---------------------------------------------------------------------- + * THERE IS NO ERROR CHECKING ON PURPOSE. IT IS POSSIBLE TO CALCULATE HOW + * MANY LOCAL LCP RECORDS THERE SHOULD BE. IT SHOULD NEVER HAPPEN THAT + * THERE IS NO ONE FREE. IF THERE IS NO ONE IT WILL ALSO BE A POINTER + * OUT OF RANGE WHICH IS AN ERROR CODE IN ITSELF. REUSES ERROR + * HANDLING IN AXE VM. + * ---------------------------------------------------------------------- */ + seizeLcpLoc(signal); + initLcpLocAcc(signal, fragId); + lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_ACC_STARTED; + signal->theData[0] = lcpPtr.p->lcpAccptr; + signal->theData[1] = lcpLocptr.i; + signal->theData[2] = lcpLocptr.p->locFragid; + signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.lcpId % MAX_LCP_STORED; + sendSignal(fragptr.p->accBlockref, GSN_ACC_SRREQ, signal, 4, JBB); + seizeLcpLoc(signal); + initLcpLocTup(signal, fragId); + lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_TUP_STARTED; + signal->theData[0] = lcpLocptr.i; + signal->theData[1] = cownref; + signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + signal->theData[3] = lcpLocptr.p->locFragid; + signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + sendSignal(fragptr.p->tupBlockref, GSN_TUP_SRREQ, signal, 5, JBB); + }//for + lcpPtr.p->lcpState = LcpRecord::LCP_SR_STARTED; + return; +}//Dblqh::execSR_FRAGIDCONF() + +/* ***************> */ +/* SR_FRAGIDREF > */ +/* ***************> */ +void Dblqh::execSR_FRAGIDREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execSR_FRAGIDREF() + +/* ************>> */ +/* ACC_SRCONF > */ +/* ************>> */ +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = SR_ACC_STARTED + * -------------------------------------------------------------------------- */ +void Dblqh::execACC_SRCONF(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (lcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { + jam(); + systemErrorLab(signal); + return; + }//if + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE + * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ------------------------------------------------------------------------ */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_ACC_COMPLETED; + srCompletedLab(signal); + return; +}//Dblqh::execACC_SRCONF() + +/* ************> */ +/* ACC_SRREF > */ +/* ************> */ +void Dblqh::execACC_SRREF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + systemErrorLab(signal); + return; +}//Dblqh::execACC_SRREF() + +/* ************>> */ +/* TUP_SRCONF > */ +/* ************>> */ +/* -------------------------------------------------------------------------- + * PRECONDITION: LCP_LOCPTR:LCP_LOCSTATE = SR_TUP_STARTED + * -------------------------------------------------------------------------- */ +void Dblqh::execTUP_SRCONF(Signal* signal) +{ + jamEntry(); + lcpLocptr.i = signal->theData[0]; + ptrCheckGuard(lcpLocptr, clcpLocrecFileSize, lcpLocRecord); + Uint32 tupFragPtr = signal->theData[1]; + ndbrequire(lcpLocptr.p->lcpLocstate == LcpLocRecord::SR_TUP_STARTED); + + lcpPtr.i = lcpLocptr.p->masterLcpRec; + ptrCheckGuard(lcpPtr, clcpFileSize, lcpRecord); + /* ------------------------------------------------------------------------ + * NO ERROR CHECK ON USING VALUE IN MASTER_LCP_REC. ERROR IN THIS REFERENCE + * WILL CAUSE POINTER OUT OF RANGE WHICH CAUSES A SYSTEM RESTART. + * ------------------------------------------------------------------------ */ + lcpLocptr.p->lcpLocstate = LcpLocRecord::SR_TUP_COMPLETED; + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (lcpLocptr.i == lcpPtr.p->firstLcpLocTup) { + jam(); + fragptr.p->tupFragptr[1] = tupFragPtr; + } else { + jam(); + fragptr.p->tupFragptr[0] = tupFragPtr; + }//if + srCompletedLab(signal); + return; +}//Dblqh::execTUP_SRCONF() + +void Dblqh::srCompletedLab(Signal* signal) +{ + checkSrCompleted(signal); + if (lcpPtr.p->lcpState == LcpRecord::LCP_SR_COMPLETED) { + jam(); + /* ---------------------------------------------------------------------- + * THE SYSTEM RESTART OF THIS FRAGMENT HAS BEEN COMPLETED. IT IS NOW + * TIME TO START A SYSTEM RESTART ON THE NEXT FRAGMENT OR CONTINUE + * WITH THE NEXT STEP OF THE SYSTEM RESTART. THIS STEP IS TO EXECUTE + * THE FRAGMENT LOGS. + * ---------------------------------------------------------------------- + * WE RELEASE THE LOCAL LCP RECORDS. + * --------------------------------------------------------------------- */ + releaseLocalLcps(signal); + /* ---------------------------------------------------------------------- + * PUT FRAGMENT ON LIST OF FRAGMENTS WHICH HAVE BEEN STARTED AS PART OF + * THE SYSTEM RESTART. THEY ARE NOW WAITING TO EXECUTE THE FRAGMENT LOG. + * --------------------------------------------------------------------- */ + fragptr.i = lcpPtr.p->currentFragment.fragPtrI; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->nextFrag = cfirstCompletedFragSr; + cfirstCompletedFragSr = fragptr.i; + if (cfirstWaitFragSr != RNIL) { + jam(); + /* -------------------------------------------------------------------- + * ANOTHER FRAGMENT IS WAITING FOR SYSTEM RESTART. RESTART THIS + * FRAGMENT AS WELL. + * -------------------------------------------------------------------- */ + fragptr.i = cfirstWaitFragSr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + cfirstWaitFragSr = fragptr.p->nextFrag; + /* -------------------------------------------------------------------- + * RETRIEVE DATA FROM THE FRAGMENT RECORD. + * -------------------------------------------------------------------- */ + ndbrequire(fragptr.p->srChkpnr < MAX_LCP_STORED); + initLcpSr(signal, + fragptr.p->srChkpnr, + fragptr.p->lcpId[fragptr.p->srChkpnr], + fragptr.p->tabRef, + fragptr.p->fragId, + fragptr.i); + signal->theData[0] = lcpPtr.i; + signal->theData[1] = cownref; + signal->theData[2] = lcpPtr.p->currentFragment.lcpFragOrd.lcpNo; + signal->theData[3] = lcpPtr.p->currentFragment.lcpFragOrd.tableId; + signal->theData[4] = lcpPtr.p->currentFragment.lcpFragOrd.fragmentId; + sendSignal(fragptr.p->accBlockref, GSN_SR_FRAGIDREQ, signal, 5, JBB); + return; + } else { + jam(); + /* -------------------------------------------------------------------- + * NO MORE FRAGMENTS ARE WAITING FOR SYSTEM RESTART. + * -------------------------------------------------------------------- */ + lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; + if (cstartRecReq == ZTRUE) { + jam(); + /* ---------------------------------------------------------------- + * WE HAVE ALSO RECEIVED AN INDICATION THAT NO MORE FRAGMENTS + * NEEDS RESTART. + * NOW IT IS TIME TO START EXECUTING THE UNDO LOG. + * ---------------------------------------------------------------- + * WE ARE NOW IN A POSITION TO ORDER TUP AND ACC TO START + * EXECUTING THEIR UNDO LOGS. THIS MUST BE DONE BEFORE THE + * FRAGMENT LOGS CAN BE EXECUTED. + * ---------------------------------------------------------------- */ + csrExecUndoLogState = EULS_STARTED; + signal->theData[0] = caccBlockref; + signal->theData[1] = cownref; + sendSignal(caccBlockref, GSN_START_RECREQ, signal, 2, JBB); + signal->theData[0] = ctupBlockref; + signal->theData[1] = cownref; + sendSignal(ctupBlockref, GSN_START_RECREQ, signal, 2, JBB); + return; + } else { + jam(); + /* ---------------------------------------------------------------- + * WE HAVE NOT RECEIVED ALL FRAGMENTS YET OR AT LEAST NOT WE + * HAVE NOT RECEIVED THE START_RECREQ SIGNAL. EXIT AND WAIT + * FOR MORE. + * ---------------------------------------------------------------- */ + return; + }//if + }//if + }//if + /*---------------*/ + /* ELSE */ + /*------------------------------------------------------------------------- + * THE SYSTEM RESTART ON THIS FRAGMENT HAS NOT BEEN COMPLETED, + * EXIT AND WAIT FOR MORE SIGNALS + *------------------------------------------------------------------------- + * DO NOTHING, EXIT IS EXECUTED BELOW + *------------------------------------------------------------------------- */ + return; +}//Dblqh::srCompletedLab() + +/* ************> */ +/* TUP_SRREF > */ +/* ************> */ +void Dblqh::execTUP_SRREF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + systemErrorLab(signal); + return; +}//Dblqh::execTUP_SRREF() + +/* ***************> */ +/* START_RECREQ > */ +/* ***************> */ +void Dblqh::execSTART_RECREQ(Signal* signal) +{ + CRASH_INSERTION(5027); + + jamEntry(); + StartRecReq * const req = (StartRecReq*)&signal->theData[0]; + cmasterDihBlockref = req->senderRef; + + crestartOldestGci = req->keepGci; + crestartNewestGci = req->lastCompletedGci; + cnewestGci = req->newestGci; + + ndbrequire(req->receivingNodeId == cownNodeid); + + cnewestCompletedGci = cnewestGci; + cstartRecReq = ZTRUE; + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; + }//for + /* ------------------------------------------------------------------------ + * WE HAVE TO SET THE OLDEST AND THE NEWEST GLOBAL CHECKPOINT IDENTITY + * THAT WILL SURVIVE THIS SYSTEM RESTART. THIS IS NEEDED SO THAT WE CAN + * SET THE LOG HEAD AND LOG TAIL PROPERLY BEFORE STARTING THE SYSTEM AGAIN. + * WE ALSO NEED TO SET CNEWEST_GCI TO ENSURE THAT LOG RECORDS ARE EXECUTED + * WITH A PROPER GCI. + *------------------------------------------------------------------------ */ + if (cstartType == NodeState::ST_NODE_RESTART) { + jam(); + signal->theData[0] = ZSR_PHASE3_START; + signal->theData[1] = ZSR_PHASE2_COMPLETED; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; + }//if + if(cstartType == NodeState::ST_INITIAL_NODE_RESTART){ + jam(); + StartRecConf * conf = (StartRecConf*)signal->getDataPtrSend(); + conf->startingNodeId = getOwnNodeId(); + sendSignal(cmasterDihBlockref, GSN_START_RECCONF, signal, + StartRecConf::SignalLength, JBB); + return; + }//if + if (cfirstWaitFragSr == RNIL) { + /* ---------------------------------------------------------------------- + * THERE ARE NO FRAGMENTS WAITING TO BE RESTARTED. + * --------------------------------------------------------------------- */ + lcpPtr.i = 0; + ptrAss(lcpPtr, lcpRecord); + if (lcpPtr.p->lcpState == LcpRecord::LCP_IDLE) { + jam(); + /* -------------------------------------------------------------------- + * THERE ARE NO FRAGMENTS THAT ARE CURRENTLY PERFORMING THEIR + * SYSTEM RESTART. + * -------------------------------------------------------------------- + * WE ARE NOW IN A POSITION TO ORDER TUP AND ACC TO START EXECUTING + * THEIR UNDO LOGS. THIS MUST BE DONE BEFORE THE FRAGMENT LOGS + * CAN BE EXECUTED. + * ------------------------------------------------------------------- */ + csrExecUndoLogState = EULS_STARTED; + signal->theData[0] = caccBlockref; + signal->theData[1] = cownref; + sendSignal(caccBlockref, GSN_START_RECREQ, signal, 2, JBB); + signal->theData[0] = ctupBlockref; + signal->theData[1] = cownref; + sendSignal(ctupBlockref, GSN_START_RECREQ, signal, 2, JBB); + }//if + }//if + /* ----------------------------------------------------------------------- + * EXIT AND WAIT FOR COMPLETION OF ALL FRAGMENTS. + * ----------------------------------------------------------------------- */ + return; +}//Dblqh::execSTART_RECREQ() + +/* ***************>> */ +/* START_RECCONF > */ +/* ***************>> */ +void Dblqh::execSTART_RECCONF(Signal* signal) +{ + jamEntry(); + BlockReference userRef = signal->theData[0]; + if (userRef == caccBlockref) { + if (csrExecUndoLogState == EULS_STARTED) { + jam(); + csrExecUndoLogState = EULS_ACC_COMPLETED; + } else { + ndbrequire(csrExecUndoLogState == EULS_TUP_COMPLETED); + jam(); + csrExecUndoLogState = EULS_COMPLETED; + /* -------------------------------------------------------------------- + * START THE FIRST PHASE OF EXECUTION OF THE LOG. + * ------------------------------------------------------------------- */ + startExecSr(signal); + }//if + } else { + ndbrequire(userRef == ctupBlockref); + if (csrExecUndoLogState == EULS_STARTED) { + jam(); + csrExecUndoLogState = EULS_TUP_COMPLETED; + } else { + ndbrequire(csrExecUndoLogState == EULS_ACC_COMPLETED); + jam(); + csrExecUndoLogState = EULS_COMPLETED; + /* -------------------------------------------------------------------- + * START THE FIRST PHASE OF EXECUTION OF THE LOG. + * ------------------------------------------------------------------- */ + startExecSr(signal); + }//if + }//if + return; +}//Dblqh::execSTART_RECCONF() + +/* ***************> */ +/* START_RECREF > */ +/* ***************> */ +void Dblqh::execSTART_RECREF(Signal* signal) +{ + jamEntry(); + ndbrequire(false); +}//Dblqh::execSTART_RECREF() + +/* ***************>> */ +/* START_EXEC_SR > */ +/* ***************>> */ +void Dblqh::execSTART_EXEC_SR(Signal* signal) +{ + FragrecordPtr prevFragptr; + jamEntry(); + fragptr.i = signal->theData[0]; + prevFragptr.i = signal->theData[1]; + if (fragptr.i == RNIL) { + jam(); + ndbrequire(cnoOfNodes < MAX_NDB_NODES); + /* ---------------------------------------------------------------------- + * NO MORE FRAGMENTS TO START EXECUTING THE LOG ON. + * SEND EXEC_SRREQ TO ALL LQH TO INDICATE THAT THIS NODE WILL + * NOT REQUEST ANY MORE FRAGMENTS TO EXECUTE THE FRAGMENT LOG ON. + * ---------------------------------------------------------------------- + * WE NEED TO SEND THOSE SIGNALS EVEN IF WE HAVE NOT REQUESTED + * ANY FRAGMENTS PARTICIPATE IN THIS PHASE. + * --------------------------------------------------------------------- */ + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + if (cnodeStatus[i] == ZNODE_UP) { + jam(); + ndbrequire(cnodeData[i] < MAX_NDB_NODES); + BlockReference ref = calcLqhBlockRef(cnodeData[i]); + signal->theData[0] = cownNodeid; + sendSignal(ref, GSN_EXEC_SRREQ, signal, 1, JBB); + }//if + }//for + } else { + jam(); + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (fragptr.p->srNoLognodes > csrPhasesCompleted) { + jam(); + Uint32 index = csrPhasesCompleted; + arrGuard(index, 4); + BlockReference ref = calcLqhBlockRef(fragptr.p->srLqhLognode[index]); + fragptr.p->srStatus = Fragrecord::SS_STARTED; + /* -------------------------------------------------------------------- + * SINCE WE CAN HAVE SEVERAL LQH NODES PER FRAGMENT WE CALCULATE + * THE LQH POINTER IN SUCH A WAY THAT WE CAN DEDUCE WHICH OF THE + * LQH NODES THAT HAS RESPONDED WHEN EXEC_FRAGCONF IS RECEIVED. + * ------------------------------------------------------------------- */ + ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; + execFragReq->userPtr = fragptr.i; + execFragReq->userRef = cownref; + execFragReq->tableId = fragptr.p->tabRef; + execFragReq->fragId = fragptr.p->fragId; + execFragReq->startGci = fragptr.p->srStartGci[index]; + execFragReq->lastGci = fragptr.p->srLastGci[index]; + sendSignal(ref, GSN_EXEC_FRAGREQ, signal, ExecFragReq::SignalLength, JBB); + prevFragptr.i = fragptr.i; + fragptr.i = fragptr.p->nextFrag; + } else { + jam(); + /* -------------------------------------------------------------------- + * THIS FRAGMENT IS NOW FINISHED WITH THE SYSTEM RESTART. IT DOES + * NOT NEED TO PARTICIPATE IN ANY MORE PHASES. REMOVE IT FROM THE + * LIST OF COMPLETED FRAGMENTS TO EXECUTE THE LOG ON. + * ALSO SEND START_FRAGCONF TO DIH AND SET THE STATE TO ACTIVE ON THE + * FRAGMENT. + * ------------------------------------------------------------------- */ + Uint32 next = fragptr.p->nextFrag; + if (prevFragptr.i != RNIL) { + jam(); + ptrCheckGuard(prevFragptr, cfragrecFileSize, fragrecord); + prevFragptr.p->nextFrag = next; + } else { + jam(); + cfirstCompletedFragSr = next; + }//if + + /** + * Put fragment on list which has completed REDO log + */ + fragptr.p->nextFrag = c_redo_log_complete_frags; + c_redo_log_complete_frags = fragptr.i; + + fragptr.p->fragStatus = Fragrecord::FSACTIVE; + fragptr.p->logFlag = Fragrecord::STATE_TRUE; + signal->theData[0] = fragptr.p->srUserptr; + signal->theData[1] = cownNodeid; + sendSignal(fragptr.p->srBlockref, GSN_START_FRAGCONF, signal, 2, JBB); + /* -------------------------------------------------------------------- + * WE HAVE TO ENSURE THAT THIS FRAGMENT IS NOT PUT BACK ON THE LIST BY + * MISTAKE. WE DO THIS BY ALSO REMOVING IT AS PREVIOUS IN START_EXEC_SR + * THIS IS PERFORMED BY KEEPING PREV_FRAGPTR AS PREV_FRAGPTR BUT MOVING + * FRAGPTR TO THE NEXT FRAGMENT IN THE LIST. + * ------------------------------------------------------------------- */ + fragptr.i = next; + }//if + signal->theData[0] = fragptr.i; + signal->theData[1] = prevFragptr.i; + sendSignal(cownref, GSN_START_EXEC_SR, signal, 2, JBB); + }//if + return; +}//Dblqh::execSTART_EXEC_SR() + +/* ***************> */ +/* EXEC_FRAGREQ > */ +/* ***************> */ +/* -------------------------------------------------------------------------- + * THIS SIGNAL IS USED TO REQUEST THAT A FRAGMENT PARTICIPATES IN EXECUTING + * THE LOG IN THIS NODE. + * ------------------------------------------------------------------------- */ +void Dblqh::execEXEC_FRAGREQ(Signal* signal) +{ + ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; + jamEntry(); + tabptr.i = execFragReq->tableId; + Uint32 fragId = execFragReq->fragId; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + if (!getFragmentrec(signal, fragId)) { + jam(); + if (!insertFragrec(signal, fragId)) { + jam(); + sendExecFragRefLab(signal); + return; + }//if + initFragrec(signal, tabptr.i, fragId, ZLOG_NODE); + fragptr.p->execSrStatus = Fragrecord::ACTIVE_REMOVE_AFTER; + } else { + jam(); + if (fragptr.p->execSrStatus == Fragrecord::ACTIVE_REMOVE_AFTER) { + jam(); + fragptr.p->execSrStatus = Fragrecord::ACTIVE_REMOVE_AFTER; + } else { + jam(); + }//if + }//if + ndbrequire(fragptr.p->execSrNoReplicas < 4); + fragptr.p->execSrBlockref[fragptr.p->execSrNoReplicas] = execFragReq->userRef; + fragptr.p->execSrUserptr[fragptr.p->execSrNoReplicas] = execFragReq->userPtr; + fragptr.p->execSrStartGci[fragptr.p->execSrNoReplicas] = execFragReq->startGci; + fragptr.p->execSrLastGci[fragptr.p->execSrNoReplicas] = execFragReq->lastGci; + fragptr.p->execSrStatus = Fragrecord::ACTIVE; + fragptr.p->execSrNoReplicas++; + cnoFragmentsExecSr++; + return; +}//Dblqh::execEXEC_FRAGREQ() + +void Dblqh::sendExecFragRefLab(Signal* signal) +{ + ExecFragReq * const execFragReq = (ExecFragReq *)&signal->theData[0]; + BlockReference retRef = execFragReq->userRef; + Uint32 retPtr = execFragReq->userPtr; + + signal->theData[0] = retPtr; + signal->theData[1] = terrorCode; + sendSignal(retRef, GSN_EXEC_FRAGREF, signal, 2, JBB); + return; +}//Dblqh::sendExecFragRefLab() + +/* ***************>> */ +/* EXEC_FRAGCONF > */ +/* ***************>> */ +void Dblqh::execEXEC_FRAGCONF(Signal* signal) +{ + jamEntry(); + fragptr.i = signal->theData[0]; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->srStatus = Fragrecord::SS_COMPLETED; + return; +}//Dblqh::execEXEC_FRAGCONF() + +/* ***************> */ +/* EXEC_FRAGREF > */ +/* ***************> */ +void Dblqh::execEXEC_FRAGREF(Signal* signal) +{ + jamEntry(); + terrorCode = signal->theData[1]; + systemErrorLab(signal); + return; +}//Dblqh::execEXEC_FRAGREF() + +/* *************** */ +/* EXEC_SRCONF > */ +/* *************** */ +void Dblqh::execEXEC_SRCONF(Signal* signal) +{ + jamEntry(); + Uint32 nodeId = signal->theData[0]; + arrGuard(nodeId, MAX_NDB_NODES); + cnodeExecSrState[nodeId] = ZEXEC_SR_COMPLETED; + ndbrequire(cnoOfNodes < MAX_NDB_NODES); + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + if (cnodeStatus[i] == ZNODE_UP) { + jam(); + nodeId = cnodeData[i]; + arrGuard(nodeId, MAX_NDB_NODES); + if (cnodeExecSrState[nodeId] != ZEXEC_SR_COMPLETED) { + jam(); + /* ------------------------------------------------------------------ + * ALL NODES HAVE NOT REPORTED COMPLETION OF EXECUTING FRAGMENT + * LOGS YET. + * ----------------------------------------------------------------- */ + return; + }//if + }//if + }//for + /* ------------------------------------------------------------------------ + * CLEAR NODE SYSTEM RESTART EXECUTION STATE TO PREPARE FOR NEXT PHASE OF + * LOG EXECUTION. + * ----------------------------------------------------------------------- */ + for (nodeId = 0; nodeId < MAX_NDB_NODES; nodeId++) { + cnodeExecSrState[nodeId] = ZSTART_SR; + }//for + /* ------------------------------------------------------------------------ + * NOW CHECK IF ALL FRAGMENTS IN THIS PHASE HAVE COMPLETED. IF SO START THE + * NEXT PHASE. + * ----------------------------------------------------------------------- */ + fragptr.i = cfirstCompletedFragSr; + if (fragptr.i == RNIL) { + jam(); + execSrCompletedLab(signal); + return; + }//if + do { + jam(); + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + ndbrequire(fragptr.p->srStatus == Fragrecord::SS_COMPLETED); + fragptr.i = fragptr.p->nextFrag; + } while (fragptr.i != RNIL); + execSrCompletedLab(signal); + return; +}//Dblqh::execEXEC_SRCONF() + +void Dblqh::execSrCompletedLab(Signal* signal) +{ + csrPhasesCompleted++; + /* ------------------------------------------------------------------------ + * ALL FRAGMENTS WERE COMPLETED. THIS PHASE IS COMPLETED. IT IS NOW TIME TO + * START THE NEXT PHASE. + * ----------------------------------------------------------------------- */ + if (csrPhasesCompleted >= 4) { + jam(); + /* ---------------------------------------------------------------------- + * THIS WAS THE LAST PHASE. WE HAVE NOW COMPLETED THE EXECUTION THE + * FRAGMENT LOGS IN ALL NODES. BEFORE WE SEND START_RECCONF TO THE + * MASTER DIH TO INDICATE A COMPLETED SYSTEM RESTART IT IS NECESSARY + * TO FIND THE HEAD AND THE TAIL OF THE LOG WHEN NEW OPERATIONS START + * TO COME AGAIN. + * + * THE FIRST STEP IS TO FIND THE HEAD AND TAIL MBYTE OF EACH LOG PART. + * TO DO THIS WE REUSE THE CONTINUEB SIGNAL SR_LOG_LIMITS. THEN WE + * HAVE TO FIND THE ACTUAL PAGE NUMBER AND PAGE INDEX WHERE TO + * CONTINUE WRITING THE LOG AFTER THE SYSTEM RESTART. + * --------------------------------------------------------------------- */ + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED; + logPartPtr.p->logLastGci = crestartNewestGci; + logPartPtr.p->logStartGci = crestartOldestGci; + logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP; + if (logPartPtr.p->headFileNo == ZNIL) { + jam(); + /* ----------------------------------------------------------------- + * IF WE HAVEN'T FOUND ANY HEAD OF THE LOG THEN WE ARE IN SERIOUS + * PROBLEM. THIS SHOULD NOT OCCUR. IF IT OCCURS ANYWAY THEN WE + * HAVE TO FIND A CURE FOR THIS PROBLEM. + * ----------------------------------------------------------------- */ + systemErrorLab(signal); + return; + }//if + signal->theData[0] = ZSR_LOG_LIMITS; + signal->theData[1] = logPartPtr.i; + signal->theData[2] = logPartPtr.p->lastLogfile; + signal->theData[3] = logPartPtr.p->lastMbyte; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); + }//for + return; + } else { + jam(); + /* ---------------------------------------------------------------------- + * THERE ARE YET MORE PHASES TO RESTART. + * WE MUST INITIALISE DATA FOR NEXT PHASE AND SEND START SIGNAL. + * --------------------------------------------------------------------- */ + startExecSr(signal); + }//if + return; +}//Dblqh::execSrCompletedLab() + +/* ************>> */ +/* EXEC_SRREQ > */ +/* ************>> */ +void Dblqh::execEXEC_SRREQ(Signal* signal) +{ + jamEntry(); + Uint32 nodeId = signal->theData[0]; + ndbrequire(nodeId < MAX_NDB_NODES); + cnodeSrState[nodeId] = ZEXEC_SR_COMPLETED; + ndbrequire(cnoOfNodes < MAX_NDB_NODES); + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + if (cnodeStatus[i] == ZNODE_UP) { + jam(); + nodeId = cnodeData[i]; + if (cnodeSrState[nodeId] != ZEXEC_SR_COMPLETED) { + jam(); + /* ------------------------------------------------------------------ + * ALL NODES HAVE NOT REPORTED COMPLETION OF SENDING EXEC_FRAGREQ YET. + * ----------------------------------------------------------------- */ + return; + }//if + }//if + }//for + /* ------------------------------------------------------------------------ + * CLEAR NODE SYSTEM RESTART STATE TO PREPARE FOR NEXT PHASE OF LOG + * EXECUTION + * ----------------------------------------------------------------------- */ + for (nodeId = 0; nodeId < MAX_NDB_NODES; nodeId++) { + cnodeSrState[nodeId] = ZSTART_SR; + }//for + if (csrPhasesCompleted != 0) { + /* ---------------------------------------------------------------------- + * THE FIRST PHASE MUST ALWAYS EXECUTE THE LOG. + * --------------------------------------------------------------------- */ + if (cnoFragmentsExecSr == 0) { + jam(); + /* -------------------------------------------------------------------- + * THERE WERE NO FRAGMENTS THAT NEEDED TO EXECUTE THE LOG IN THIS PHASE. + * ------------------------------------------------------------------- */ + srPhase3Comp(signal); + return; + }//if + }//if + /* ------------------------------------------------------------------------ + * NOW ALL NODES HAVE SENT ALL EXEC_FRAGREQ. NOW WE CAN START EXECUTING THE + * LOG FROM THE MINIMUM GCI NEEDED UNTIL THE MAXIMUM GCI NEEDED. + * + * WE MUST FIRST CHECK IF THE FIRST PHASE OF THE SYSTEM RESTART HAS BEEN + * COMPLETED. THIS HANDLING IS PERFORMED IN THE FILE SYSTEM MODULE + * ----------------------------------------------------------------------- */ + signal->theData[0] = ZSR_PHASE3_START; + signal->theData[1] = ZSR_PHASE2_COMPLETED; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +}//Dblqh::execEXEC_SRREQ() + +/* ######################################################################### */ +/* SYSTEM RESTART PHASE THREE MODULE */ +/* THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. */ +/* */ +/* THIS MODULE IS CONCERNED WITH EXECUTING THE FRAGMENT LOG. IT DOES ALSO */ +/* CONTAIN SIGNAL RECEPTIONS LQHKEYCONF AND LQHKEYREF SINCE LQHKEYREQ IS USED*/ +/* TO EXECUTE THE LOG RECORDS. */ +/* */ +/* BEFORE IT STARTS IT HAS BEEN DECIDED WHERE TO START AND WHERE TO STOP */ +/* READING THE FRAGMENT LOG BY USING THE INFORMATION ABOUT GCI DISCOVERED IN */ +/* PHASE ONE OF THE SYSTEM RESTART. */ +/* ######################################################################### */ +/*---------------------------------------------------------------------------*/ +/* PHASE THREE OF THE SYSTEM RESTART CAN NOW START. ONE OF THE PHASES HAVE */ +/* COMPLETED. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::srPhase3Start(Signal* signal) +{ + UintR tsrPhaseStarted; + + jamEntry(); + tsrPhaseStarted = signal->theData[0]; + if (csrPhaseStarted == ZSR_NO_PHASE_STARTED) { + jam(); + csrPhaseStarted = tsrPhaseStarted; + if (cstartType == NodeState::ST_NODE_RESTART) { + ndbrequire(cinitialStartOngoing == ZTRUE); + cinitialStartOngoing = ZFALSE; + checkStartCompletedLab(signal); + }//if + return; + }//if + ndbrequire(csrPhaseStarted != tsrPhaseStarted); + ndbrequire(csrPhaseStarted != ZSR_BOTH_PHASES_STARTED); + + csrPhaseStarted = ZSR_BOTH_PHASES_STARTED; + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_STARTED; + logPartPtr.p->logStartGci = (UintR)-1; + if (csrPhasesCompleted == 0) { + jam(); + /* -------------------------------------------------------------------- + * THE FIRST PHASE WE MUST ENSURE THAT IT REACHES THE END OF THE LOG. + * ------------------------------------------------------------------- */ + logPartPtr.p->logLastGci = crestartNewestGci; + } else { + jam(); + logPartPtr.p->logLastGci = 2; + }//if + }//for + if (cstartType == NodeState::ST_NODE_RESTART) { + jam(); + /* ---------------------------------------------------------------------- + * FOR A NODE RESTART WE HAVE NO FRAGMENTS DEFINED YET. + * THUS WE CAN SKIP THAT PART + * --------------------------------------------------------------------- */ + signal->theData[0] = ZSR_GCI_LIMITS; + signal->theData[1] = RNIL; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + } else { + jam(); + signal->theData[0] = ZSR_GCI_LIMITS; + signal->theData[1] = 0; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//if + return; +}//Dblqh::srPhase3Start() + +/* -------------------------------------------------------------------------- + * WE NOW WE NEED TO FIND THE LIMITS WITHIN WHICH TO EXECUTE + * THE FRAGMENT LOG + * ------------------------------------------------------------------------- */ +void Dblqh::srGciLimits(Signal* signal) +{ + LogPartRecordPtr tmpLogPartPtr; + + jamEntry(); + fragptr.i = signal->theData[0]; + Uint32 loopCount = 0; + logPartPtr.i = 0; + ptrAss(logPartPtr, logPartRecord); + while (fragptr.i < cfragrecFileSize) { + jam(); + ptrAss(fragptr, fragrecord); + if (fragptr.p->execSrStatus != Fragrecord::IDLE) { + jam(); + ndbrequire(fragptr.p->execSrNoReplicas - 1 < 4); + for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) { + jam(); + if (fragptr.p->execSrStartGci[i] < logPartPtr.p->logStartGci) { + jam(); + logPartPtr.p->logStartGci = fragptr.p->execSrStartGci[i]; + }//if + if (fragptr.p->execSrLastGci[i] > logPartPtr.p->logLastGci) { + jam(); + logPartPtr.p->logLastGci = fragptr.p->execSrLastGci[i]; + }//if + }//for + }//if + loopCount++; + if (loopCount > 20) { + jam(); + signal->theData[0] = ZSR_GCI_LIMITS; + signal->theData[1] = fragptr.i + 1; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; + } else { + jam(); + fragptr.i++; + }//if + }//while + if (logPartPtr.p->logStartGci == (UintR)-1) { + jam(); + /* -------------------------------------------------------------------- + * THERE WERE NO FRAGMENTS TO INSTALL WE WILL EXECUTE THE LOG AS + * SHORT AS POSSIBLE TO REACH THE END OF THE LOG. THIS WE DO BY + * STARTING AT THE STOP GCI. + * ------------------------------------------------------------------- */ + logPartPtr.p->logStartGci = logPartPtr.p->logLastGci; + }//if + for (tmpLogPartPtr.i = 1; tmpLogPartPtr.i < 4; tmpLogPartPtr.i++) { + ptrAss(tmpLogPartPtr, logPartRecord); + tmpLogPartPtr.p->logStartGci = logPartPtr.p->logStartGci; + tmpLogPartPtr.p->logLastGci = logPartPtr.p->logLastGci; + }//for + for (logPartPtr.i = 0; logPartPtr.i < 4; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_STOP; + signal->theData[0] = ZSR_LOG_LIMITS; + signal->theData[1] = logPartPtr.i; + signal->theData[2] = logPartPtr.p->lastLogfile; + signal->theData[3] = logPartPtr.p->lastMbyte; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); + }//for +}//Dblqh::srGciLimits() + +/* -------------------------------------------------------------------------- + * IT IS NOW TIME TO FIND WHERE TO START EXECUTING THE LOG. + * THIS SIGNAL IS SENT FOR EACH LOG PART AND STARTS THE EXECUTION + * OF THE LOG FOR THIS PART. + *-------------------------------------------------------------------------- */ +void Dblqh::srLogLimits(Signal* signal) +{ + Uint32 tlastPrepRef; + Uint32 tmbyte; + + jamEntry(); + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.i = signal->theData[1]; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + tmbyte = signal->theData[2]; + Uint32 loopCount = 0; + /* ------------------------------------------------------------------------ + * WE ARE SEARCHING FOR THE START AND STOP MBYTE OF THE LOG THAT IS TO BE + * EXECUTED. + * ----------------------------------------------------------------------- */ + while(true) { + ndbrequire(tmbyte < 16); + if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_STOP) { + if (logFilePtr.p->logMaxGciCompleted[tmbyte] < logPartPtr.p->logLastGci) { + jam(); + /* -------------------------------------------------------------------- + * WE ARE STEPPING BACKWARDS FROM MBYTE TO MBYTE. THIS IS THE FIRST + * MBYTE WHICH IS TO BE INCLUDED IN THE LOG EXECUTION. THE STOP GCI + * HAS NOT BEEN COMPLETED BEFORE THIS MBYTE. THUS THIS MBYTE HAVE + * TO BE EXECUTED. + * ------------------------------------------------------------------- */ + logPartPtr.p->stopLogfile = logFilePtr.i; + logPartPtr.p->stopMbyte = tmbyte; + logPartPtr.p->logExecState = LogPartRecord::LES_SEARCH_START; + }//if + }//if + /* ------------------------------------------------------------------------ + * WHEN WE HAVEN'T FOUND THE STOP MBYTE IT IS NOT NECESSARY TO LOOK FOR THE + * START MBYTE. THE REASON IS THE FOLLOWING LOGIC CHAIN: + * MAX_GCI_STARTED >= MAX_GCI_COMPLETED >= LAST_GCI >= START_GCI + * THUS MAX_GCI_STARTED >= START_GCI. THUS MAX_GCI_STARTED < START_GCI CAN + * NOT BE TRUE AS WE WILL CHECK OTHERWISE. + * ----------------------------------------------------------------------- */ + if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_START) { + if (logFilePtr.p->logMaxGciStarted[tmbyte] < logPartPtr.p->logStartGci) { + jam(); + /* -------------------------------------------------------------------- + * WE HAVE NOW FOUND THE START OF THE EXECUTION OF THE LOG. + * WE STILL HAVE TO MOVE IT BACKWARDS TO ALSO INCLUDE THE + * PREPARE RECORDS WHICH WERE STARTED IN A PREVIOUS MBYTE. + * ------------------------------------------------------------------- */ + tlastPrepRef = logFilePtr.p->logLastPrepRef[tmbyte]; + logPartPtr.p->startMbyte = tlastPrepRef & 65535; + LogFileRecordPtr locLogFilePtr; + findLogfile(signal, tlastPrepRef >> 16, logPartPtr, &locLogFilePtr); + logPartPtr.p->startLogfile = locLogFilePtr.i; + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; + }//if + }//if + if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG) { + if (tmbyte == 0) { + jam(); + tmbyte = ZNO_MBYTES_IN_FILE - 1; + logFilePtr.i = logFilePtr.p->prevLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + } else { + jam(); + tmbyte--; + }//if + if (logPartPtr.p->lastLogfile == logFilePtr.i) { + ndbrequire(logPartPtr.p->lastMbyte != tmbyte); + }//if + if (loopCount > 20) { + jam(); + signal->theData[0] = ZSR_LOG_LIMITS; + signal->theData[1] = logPartPtr.i; + signal->theData[2] = logFilePtr.i; + signal->theData[3] = tmbyte; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); + return; + }//if + loopCount++; + } else { + jam(); + break; + }//if + }//while + /* ------------------------------------------------------------------------ + * WE HAVE NOW FOUND BOTH THE START AND THE STOP OF THE LOG. NOW START + * EXECUTING THE LOG. THE FIRST ACTION IS TO OPEN THE LOG FILE WHERE TO + * START EXECUTING THE LOG. + * ----------------------------------------------------------------------- */ + if (logPartPtr.p->logPartState == LogPartRecord::SR_THIRD_PHASE_STARTED) { + jam(); + logFilePtr.i = logPartPtr.p->startLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_START; + openFileRw(signal, logFilePtr); + } else { + jam(); + ndbrequire(logPartPtr.p->logPartState == LogPartRecord::SR_FOURTH_PHASE_STARTED); + /* -------------------------------------------------------------------- + * WE HAVE NOW FOUND THE TAIL MBYTE IN THE TAIL FILE. + * SET THOSE PARAMETERS IN THE LOG PART. + * WE HAVE ALSO FOUND THE HEAD MBYTE. WE STILL HAVE TO SEARCH + * FOR THE PAGE NUMBER AND PAGE INDEX WHERE TO SET THE HEAD. + * ------------------------------------------------------------------- */ + logFilePtr.i = logPartPtr.p->startLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPartPtr.p->logTailFileNo = logFilePtr.p->fileNo; + logPartPtr.p->logTailMbyte = logPartPtr.p->startMbyte; + /* -------------------------------------------------------------------- + * THE HEAD WE ACTUALLY FOUND DURING EXECUTION OF LOG SO WE USE + * THIS INFO HERE RATHER THAN THE MBYTE WE FOUND TO BE THE HEADER. + * ------------------------------------------------------------------- */ + LogFileRecordPtr locLogFilePtr; + findLogfile(signal, logPartPtr.p->headFileNo, logPartPtr, &locLogFilePtr); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE; + openFileRw(signal, locLogFilePtr); + }//if + return; +}//Dblqh::srLogLimits() + +void Dblqh::openExecSrStartLab(Signal* signal) +{ + logPartPtr.p->currentLogfile = logFilePtr.i; + logFilePtr.p->currentMbyte = logPartPtr.p->startMbyte; + /* ------------------------------------------------------------------------ + * WE NEED A TC CONNECT RECORD TO HANDLE EXECUTION OF LOG RECORDS. + * ------------------------------------------------------------------------ */ + seizeTcrec(); + logPartPtr.p->logTcConrec = tcConnectptr.i; + /* ------------------------------------------------------------------------ + * THE FIRST LOG RECORD TO EXECUTE IS ALWAYS AT A NEW MBYTE. + * SET THE NUMBER OF PAGES IN THE MAIN MEMORY BUFFER TO ZERO AS AN INITIAL + * VALUE. THIS VALUE WILL BE UPDATED AND ENSURED THAT IT RELEASES PAGES IN + * THE SUBROUTINE READ_EXEC_SR. + * ----------------------------------------------------------------------- */ + logPartPtr.p->mmBufferSize = 0; + readExecSrNewMbyte(signal); + return; +}//Dblqh::openExecSrStartLab() + +/* --------------------------------------------------------------------------- + * WE WILL ALWAYS ENSURE THAT WE HAVE AT LEAST 16 KBYTE OF LOG PAGES WHEN WE + * START READING A LOG RECORD. THE ONLY EXCEPTION IS WHEN WE COME CLOSE TO A + * MBYTE BOUNDARY. SINCE WE KNOW THAT LOG RECORDS ARE NEVER WRITTEN ACROSS A + * MBYTE BOUNDARY THIS IS NOT A PROBLEM. + * + * WE START BY READING 64 KBYTE BEFORE STARTING TO EXECUTE THE LOG RECORDS. + * WHEN WE COME BELOW 64 KBYTE WE READ ANOTHER SET OF LOG PAGES. WHEN WE + * GO BELOW 16 KBYTE WE WAIT UNTIL THE READ PAGES HAVE ENTERED THE BLOCK. + * ------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + * NEW PAGES FROM LOG FILE DURING EXECUTION OF LOG HAS ARRIVED. + * ------------------------------------------------------------------------- */ +void Dblqh::readExecSrLab(Signal* signal) +{ + buildLinkedLogPageList(signal); + /* ------------------------------------------------------------------------ + * WE NEED TO SET THE CURRENT PAGE INDEX OF THE FIRST PAGE SINCE IT CAN BE + * USED IMMEDIATELY WITHOUT ANY OTHER INITIALISATION. THE REST OF THE PAGES + * WILL BE INITIALISED BY READ_LOGWORD. + * ----------------------------------------------------------------------- */ + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; + if (logPartPtr.p->logExecState == + LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE) { + jam(); + /* ---------------------------------------------------------------------- + * THIS IS THE FIRST READ DURING THE EXECUTION OF THIS MBYTE. SET THE + * NEW CURRENT LOG PAGE TO THE FIRST OF THESE PAGES. CHANGE + * LOG_EXEC_STATE TO ENSURE THAT WE START EXECUTION OF THE LOG. + * --------------------------------------------------------------------- */ + logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte * + ZPAGES_IN_MBYTE; + logPartPtr.p->prevFilepage = logFilePtr.p->currentFilepage; + logFilePtr.p->currentLogpage = lfoPtr.p->firstLfoPage; + logPartPtr.p->prevLogpage = logFilePtr.p->currentLogpage; + }//if + moveToPageRef(signal); + releaseLfo(signal); + /* ------------------------------------------------------------------------ + * NOW WE HAVE COMPLETED THE RECEPTION OF THESE PAGES. + * NOW CHECK IF WE NEED TO READ MORE PAGES. + * ----------------------------------------------------------------------- */ + checkReadExecSr(signal); + if (logPartPtr.p->logExecState == LogPartRecord::LES_EXEC_LOG) { + jam(); + signal->theData[0] = ZEXEC_SR; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; + }//if + return; +}//Dblqh::readExecSrLab() + +void Dblqh::openExecSrNewMbyteLab(Signal* signal) +{ + readExecSrNewMbyte(signal); + return; +}//Dblqh::openExecSrNewMbyteLab() + +void Dblqh::closeExecSrLab(Signal* signal) +{ + LogFileRecordPtr locLogFilePtr; + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + logPartPtr.i = logFilePtr.p->logPartRec; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + locLogFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE; + openFileRw(signal, locLogFilePtr); + return; +}//Dblqh::closeExecSrLab() + +void Dblqh::writeDirtyLab(Signal* signal) +{ + releaseLfo(signal); + signal->theData[0] = logPartPtr.i; + execSr(signal); + return; +}//Dblqh::writeDirtyLab() + +/* -------------------------------------------------------------------------- + * EXECUTE A LOG RECORD WITHIN THE CURRENT MBYTE. + * ------------------------------------------------------------------------- */ +void Dblqh::execSr(Signal* signal) +{ + LogFileRecordPtr nextLogFilePtr; + LogPageRecordPtr tmpLogPagePtr; + Uint32 logWord; + + jamEntry(); + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + + do { + jam(); + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logPartPtr.p->prevLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + if (logPagePtr.p->logPageWord[ZPOS_DIRTY] == ZDIRTY) { + jam(); + switch (logPartPtr.p->logExecState) { + case LogPartRecord::LES_EXEC_LOG_COMPLETED: + case LogPartRecord::LES_EXEC_LOG_NEW_FILE: + case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE: + jam(); + /* ------------------------------------------------------------------ + * IN THIS WE HAVE COMPLETED EXECUTION OF THE CURRENT LOG PAGE + * AND CAN WRITE IT TO DISK SINCE IT IS DIRTY. + * ----------------------------------------------------------------- */ + writeDirty(signal); + return; + break; + case LogPartRecord::LES_EXEC_LOG: + jam(); + /* -------------------------------------------------------------------- + * IN THIS CASE WE ONLY WRITE THE PAGE TO DISK IF WE HAVE COMPLETED + * EXECUTION OF LOG RECORDS BELONGING TO THIS LOG PAGE. + * ------------------------------------------------------------------- */ + if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { + jam(); + writeDirty(signal); + return; + }//if + break; + default: + ndbrequire(false); + break; + }//switch + }//if + if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { + jam(); + logPartPtr.p->prevLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + logPartPtr.p->prevFilepage++; + continue; + }//if + switch (logPartPtr.p->logExecState) { + case LogPartRecord::LES_EXEC_LOG_COMPLETED: + jam(); + releaseMmPages(signal); + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR_COMPLETED; + closeFile(signal, logFilePtr); + return; + break; + case LogPartRecord::LES_EXEC_LOG_NEW_MBYTE: + jam(); + logFilePtr.p->currentMbyte++; + readExecSrNewMbyte(signal); + return; + break; + case LogPartRecord::LES_EXEC_LOG_NEW_FILE: + jam(); + nextLogFilePtr.i = logFilePtr.p->nextLogFile; + logPartPtr.p->currentLogfile = nextLogFilePtr.i; + ptrCheckGuard(nextLogFilePtr, clogFileFileSize, logFileRecord); + nextLogFilePtr.p->currentMbyte = 0; + logFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_SR; + closeFile(signal, logFilePtr); + return; + break; + case LogPartRecord::LES_EXEC_LOG: + jam(); + /*empty*/; + break; + default: + jam(); + systemErrorLab(signal); + return; + break; + }//switch + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPartPtr.p->savePageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + if (logPartPtr.p->execSrPagesRead < ZMIN_READ_BUFFER_SIZE) { + /* -------------------------------------------------------------------- + * THERE WERE LESS THAN 16 KBYTE OF LOG PAGES REMAINING. WE WAIT UNTIL + * THE NEXT 64 KBYTE ARRIVES UNTIL WE CONTINUE AGAIN. + * ------------------------------------------------------------------- */ + if ((logPartPtr.p->execSrPagesRead + + logPartPtr.p->execSrPagesExecuted) < ZPAGES_IN_MBYTE) { + jam(); + /* ------------------------------------------------------------------ + * WE ONLY STOP AND WAIT IF THERE MORE PAGES TO READ. IF IT IS NOT + * THEN IT IS THE END OF THE MBYTE AND WE WILL CONTINUE. IT IS NO + * RISK THAT A LOG RECORD WE FIND WILL NOT BE READ AT THIS TIME + * SINCE THE LOG RECORDS NEVER SPAN OVER A MBYTE BOUNDARY. + * ----------------------------------------------------------------- */ + readExecSr(signal); + logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR; + return; + }//if + }//if + logWord = readLogword(signal); + switch (logWord) { +/* ========================================================================= */ +/* ========================================================================= */ + case ZPREP_OP_TYPE: + { + logWord = readLogword(signal); + stepAhead(signal, logWord - 2); + break; + } +/* ========================================================================= */ +/* ========================================================================= */ + case ZINVALID_COMMIT_TYPE: + jam(); + stepAhead(signal, ZCOMMIT_LOG_SIZE - 1); + break; +/* ========================================================================= */ +/* ========================================================================= */ + case ZCOMMIT_TYPE: + { + CommitLogRecord commitLogRecord; + jam(); + tcConnectptr.i = logPartPtr.p->logTcConrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + readCommitLog(signal, &commitLogRecord); + if (tcConnectptr.p->gci > crestartNewestGci) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS LOG RECORD MUST BE IGNORED. IT IS PART OF A GLOBAL CHECKPOINT WHICH */ +/* WILL BE INVALIDATED BY THE SYSTEM RESTART. IF NOT INVALIDATED IT MIGHT BE */ +/* EXECUTED IN A FUTURE SYSTEM RESTART. */ +/*---------------------------------------------------------------------------*/ + tmpLogPagePtr.i = logPartPtr.p->prevLogpage; + ptrCheckGuard(tmpLogPagePtr, clogPageFileSize, logPageRecord); + arrGuard(logPartPtr.p->savePageIndex, ZPAGE_SIZE); + tmpLogPagePtr.p->logPageWord[logPartPtr.p->savePageIndex] = + ZINVALID_COMMIT_TYPE; + tmpLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZDIRTY; + } else { + jam(); +/*---------------------------------------------------------------------------*/ +/* CHECK IF I AM SUPPOSED TO EXECUTE THIS LOG RECORD. IF I AM THEN SAVE PAGE */ +/* INDEX IN CURRENT LOG PAGE SINCE IT WILL BE OVERWRITTEN WHEN EXECUTING THE */ +/* LOG RECORD. */ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->execSrExecuteIndex = 0; + Uint32 result = checkIfExecLog(signal); + if (result == ZOK) { + jam(); +//*---------------------------------------------------------------------------*/ +/* IN A NODE RESTART WE WILL NEVER END UP HERE SINCE NO FRAGMENTS HAVE BEEN */ +/* DEFINED YET. THUS NO EXTRA CHECKING FOR NODE RESTART IS NECESSARY. */ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->savePageIndex = + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + tcConnectptr.p->fragmentptr = fragptr.i; + findPageRef(signal, &commitLogRecord); + logPartPtr.p->execSrLogPageIndex = commitLogRecord.startPageIndex; + if (logPagePtr.i != RNIL) { + jam(); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = commitLogRecord.startPageIndex; + logPartPtr.p->execSrLogPage = logPagePtr.i; + execLogRecord(signal); + return; + }//if + logPartPtr.p->execSrStartPageNo = commitLogRecord.startPageNo; + logPartPtr.p->execSrStopPageNo = commitLogRecord.stopPageNo; + findLogfile(signal, commitLogRecord.fileNo, logPartPtr, &logFilePtr); + logPartPtr.p->execSrExecLogFile = logFilePtr.i; + if (logFilePtr.i == logPartPtr.p->currentLogfile) { + jam(); + readExecLog(signal); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG; + return; + } else { + jam(); +/*---------------------------------------------------------------------------*/ +/* THE FILE IS CURRENTLY NOT OPEN. WE MUST OPEN IT BEFORE WE CAN READ FROM */ +/* THE FILE. */ +/*---------------------------------------------------------------------------*/ + logFilePtr.p->logFileStatus = LogFileRecord::OPEN_EXEC_LOG; + openFileRw(signal, logFilePtr); + return; + }//if + }//if + }//if + break; + } +/* ========================================================================= */ +/* ========================================================================= */ + case ZABORT_TYPE: + jam(); + stepAhead(signal, ZABORT_LOG_SIZE - 1); + break; +/* ========================================================================= */ +/* ========================================================================= */ + case ZFD_TYPE: + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS IS THE FIRST ITEM WE ENCOUNTER IN A NEW FILE. AT THIS MOMENT WE SHALL*/ +/* SIMPLY BYPASS IT. IT HAS NO SIGNIFANCE WHEN EXECUTING THE LOG. IT HAS ITS */ +/* SIGNIFANCE WHEN FINDING THE START END THE END OF THE LOG. */ +/* WE HARDCODE THE PAGE INDEX SINCE THIS SHOULD NEVER BE FOUND AT ANY OTHER */ +/* PLACE THAN IN THE FIRST PAGE OF A NEW FILE IN THE FIRST POSITION AFTER THE*/ +/* HEADER. */ +/*---------------------------------------------------------------------------*/ + ndbrequire(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] == + (ZPAGE_HEADER_SIZE + ZPOS_NO_FD)); + { + Uint32 noFdDescriptors = + logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_NO_FD]; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = + (ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (noFdDescriptors * ZFD_PART_SIZE); + } + break; +/* ========================================================================= */ +/* ========================================================================= */ + case ZNEXT_LOG_RECORD_TYPE: + jam(); + stepAhead(signal, ZPAGE_SIZE - logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]); + break; +/* ========================================================================= */ +/* ========================================================================= */ + case ZNEXT_MBYTE_TYPE: +/*---------------------------------------------------------------------------*/ +/* WE WILL SKIP A PART OF THE LOG FILE. ACTUALLY THE NEXT POINTER IS TO */ +/* A NEW MBYTE. THEREFORE WE WILL START UP A NEW MBYTE. THIS NEW MBYTE IS */ +/* HOWEVER ONLY STARTED IF IT IS NOT AFTER THE STOP MBYTE. */ +/* IF WE HAVE REACHED THE END OF THE STOP MBYTE THEN THE EXECUTION OF THE LOG*/ +/* IS COMPLETED. */ +/*---------------------------------------------------------------------------*/ + if (logPartPtr.p->currentLogfile == logPartPtr.p->stopLogfile) { + if (logFilePtr.p->currentMbyte == logPartPtr.p->stopMbyte) { + jam(); +/*---------------------------------------------------------------------------*/ +/* THIS WAS THE LAST MBYTE TO EXECUTE IN THIS LOG PART. WE SHOULD HAVE FOUND */ +/* A COMPLETED GCI RECORD OF THE LAST GCI BEFORE THIS. FOR SOME REASON THIS */ +/* RECORD WAS NOT AVAILABLE ON THE LOG. CRASH THE SYSTEM, A VERY SERIOUS */ +/* ERROR WHICH WE MUST REALLY WORK HARD TO AVOID. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM. */ +/*---------------------------------------------------------------------------*/ + signal->theData[0] = RNIL; + signal->theData[1] = logPartPtr.i; + Uint32 tmp = logFilePtr.p->fileName[3]; + tmp = (tmp >> 8) & 0xff;// To get the Directory, DXX. + signal->theData[2] = tmp; + signal->theData[3] = logFilePtr.p->fileNo; + signal->theData[4] = logFilePtr.p->currentFilepage; + signal->theData[5] = logFilePtr.p->currentMbyte; + signal->theData[6] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + sendSignal(cownref, GSN_DEBUG_SIG, signal, 7, JBA); + return; + }//if + }//if +/*---------------------------------------------------------------------------*/ +/* START EXECUTION OF A NEW MBYTE IN THE LOG. */ +/*---------------------------------------------------------------------------*/ + if (logFilePtr.p->currentMbyte < (ZNO_MBYTES_IN_FILE - 1)) { + jam(); + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_MBYTE; + } else { + ndbrequire(logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)); + jam(); +/*---------------------------------------------------------------------------*/ +/* WE HAVE TO CHANGE FILE. CLOSE THIS ONE AND THEN OPEN THE NEXT. */ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_NEW_FILE; + }//if + break; +/* ========================================================================= */ +/* ========================================================================= */ + case ZCOMPLETED_GCI_TYPE: + jam(); + logWord = readLogword(signal); + if (logWord == logPartPtr.p->logLastGci) { + jam(); +/*---------------------------------------------------------------------------*/ +/* IF IT IS THE LAST GCI TO LIVE AFTER SYSTEM RESTART THEN WE RECORD THE NEXT*/ +/* WORD AS THE NEW HEADER OF THE LOG FILE. OTHERWISE WE SIMPLY IGNORE THIS */ +/* LOG RECORD. */ +/*---------------------------------------------------------------------------*/ + if (csrPhasesCompleted == 0) { + jam(); +/*---------------------------------------------------------------------------*/ +/*WE ONLY RECORD THE HEAD OF THE LOG IN THE FIRST LOG ROUND OF LOG EXECUTION.*/ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->headFileNo = logFilePtr.p->fileNo; + logPartPtr.p->headPageNo = logFilePtr.p->currentFilepage; + logPartPtr.p->headPageIndex = + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + }//if +/*---------------------------------------------------------------------------*/ +/* THERE IS NO NEED OF EXECUTING PAST THIS LINE SINCE THERE WILL ONLY BE LOG */ +/* RECORDS THAT WILL BE OF NO INTEREST. THUS CLOSE THE FILE AND START THE */ +/* NEXT PHASE OF THE SYSTEM RESTART. */ +/*---------------------------------------------------------------------------*/ + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_COMPLETED; + }//if + break; + default: + jam(); +/* ========================================================================= */ +/* ========================================================================= */ +/*---------------------------------------------------------------------------*/ +/* SEND A SIGNAL TO THE SIGNAL LOG AND THEN CRASH THE SYSTEM. */ +/*---------------------------------------------------------------------------*/ + signal->theData[0] = RNIL; + signal->theData[1] = logPartPtr.i; + Uint32 tmp = logFilePtr.p->fileName[3]; + tmp = (tmp >> 8) & 0xff;// To get the Directory, DXX. + signal->theData[2] = tmp; + signal->theData[3] = logFilePtr.p->fileNo; + signal->theData[4] = logFilePtr.p->currentMbyte; + signal->theData[5] = logFilePtr.p->currentFilepage; + signal->theData[6] = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + signal->theData[7] = logWord; + sendSignal(cownref, GSN_DEBUG_SIG, signal, 8, JBA); + return; + break; + }//switch +/*---------------------------------------------------------------------------*/ +// We continue to execute log records until we find a proper one to execute or +// that we reach a new page. +/*---------------------------------------------------------------------------*/ + } while (1); +}//Dblqh::execSr() + +/*---------------------------------------------------------------------------*/ +/* THIS SIGNAL IS ONLY RECEIVED TO BE CAPTURED IN THE SIGNAL LOG. IT IS */ +/* ALSO USED TO CRASH THE SYSTEM AFTER SENDING A SIGNAL TO THE LOG. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::execDEBUG_SIG(Signal* signal) +{ +/* +2.5 TEMPORARY VARIABLES +----------------------- +*/ + UintR tdebug; + + jamEntry(); + logPagePtr.i = signal->theData[0]; + tdebug = logPagePtr.p->logPageWord[0]; + + char buf[100]; + BaseString::snprintf(buf, 100, + "Error while reading REDO log.\n" + "D=%d, F=%d Mb=%d FP=%d W1=%d W2=%d", + signal->theData[2], signal->theData[3], signal->theData[4], + signal->theData[5], signal->theData[6], signal->theData[7]); + + progError(__LINE__, ERR_SR_REDOLOG, buf); + + return; +}//Dblqh::execDEBUG_SIG() + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void Dblqh::closeExecLogLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + signal->theData[0] = ZEXEC_SR; + signal->theData[1] = logFilePtr.p->logPartRec; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +}//Dblqh::closeExecLogLab() + +void Dblqh::openExecLogLab(Signal* signal) +{ + readExecLog(signal); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_LOG; + return; +}//Dblqh::openExecLogLab() + +void Dblqh::readExecLogLab(Signal* signal) +{ + buildLinkedLogPageList(signal); + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOGREC_FROM_FILE; + logPartPtr.p->execSrLfoRec = lfoPtr.i; + logPartPtr.p->execSrLogPage = logPagePtr.i; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = + logPartPtr.p->execSrLogPageIndex; + execLogRecord(signal); + return; +}//Dblqh::readExecLogLab() + +/*---------------------------------------------------------------------------*/ +/* THIS CODE IS USED TO EXECUTE A LOG RECORD WHEN IT'S DATA HAVE BEEN LOCATED*/ +/* AND TRANSFERRED INTO MEMORY. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::execLogRecord(Signal* signal) +{ + jamEntry(); + + tcConnectptr.i = logPartPtr.p->logTcConrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + // Read a log record and prepare it for execution + readLogHeader(signal); + readKey(signal); + readAttrinfo(signal); + initReqinfoExecSr(signal); + arrGuard(logPartPtr.p->execSrExecuteIndex, 4); + BlockReference ref = fragptr.p->execSrBlockref[logPartPtr.p->execSrExecuteIndex]; + tcConnectptr.p->nextReplica = refToNode(ref); + tcConnectptr.p->connectState = TcConnectionrec::LOG_CONNECTED; + tcConnectptr.p->tcOprec = tcConnectptr.i; + packLqhkeyreqLab(signal); + return; +}//Dblqh::execLogRecord() + +//---------------------------------------------------------------------------- +// This function invalidates log pages after the last GCI record in a +// system/node restart. This is to ensure that the end of the log is +// consistent. This function is executed last in start phase 3. +// RT 450. EDTJAMO. +//---------------------------------------------------------------------------- +void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { + + jam(); + if (logPartPtr.p->logExecState != LogPartRecord::LES_EXEC_LOG_INVALIDATE) { + jam(); + systemError(signal); + } + + if (logFilePtr.p->fileNo != logPartPtr.p->invalidateFileNo) { + jam(); + systemError(signal); + } + + switch (lfoPtr.p->lfoState) { + case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: + jam(); + releaseLfo(signal); + releaseLogpage(signal); + if (logPartPtr.p->invalidatePageNo < (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE - 1)) { + // We continue in this file. + logPartPtr.p->invalidatePageNo++; + } else { + // We continue in the next file. + logFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPartPtr.p->invalidateFileNo = logFilePtr.p->fileNo; + // Page 0 is used for file descriptors. + logPartPtr.p->invalidatePageNo = 1; + if (logFilePtr.p->logFileStatus != LogFileRecord::OPEN) { + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_INVALIDATE_PAGES; + openFileRw(signal, logFilePtr); + return; + break; + } + } + // Read a page from the log file. + readFileInInvalidate(signal); + return; + break; + + case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: + jam(); + releaseLfo(signal); + // Check if this page must be invalidated. + // If the log lap number on a page after the head of the tail is the same + // as the actual log lap number we must invalidate this page. Otherwise it + // could be impossible to find the end of the log in a later system/node + // restart. + if (logPagePtr.p->logPageWord[ZPOS_LOG_LAP] == logPartPtr.p->logLap) { + // This page must be invalidated. + logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 0; + // Contact NDBFS. Real time break. + writeSinglePage(signal, logPartPtr.p->invalidatePageNo, ZPAGE_SIZE - 1); + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; + } else { + // We are done with invalidating. Finish start phase 3.4. + exitFromInvalidate(signal); + } + return; + break; + + default: + jam(); + systemError(signal); + return; + break; + } + + return; +}//Dblqh::invalidateLogAfterLastGCI + +void Dblqh::readFileInInvalidate(Signal* signal) { + jam(); + // Contact NDBFS. Real time break. + readSinglePage(signal, logPartPtr.p->invalidatePageNo); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_INVALIDATE_PAGES; +} + +void Dblqh::exitFromInvalidate(Signal* signal) { + jam(); + // Close files if necessary. Current file and the next file should be + // left open. + if (logFilePtr.i != logPartPtr.p->currentLogfile) { + LogFileRecordPtr currentLogFilePtr; + LogFileRecordPtr nextAfterCurrentLogFilePtr; + + currentLogFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(currentLogFilePtr, clogFileFileSize, logFileRecord); + + nextAfterCurrentLogFilePtr.i = currentLogFilePtr.p->nextLogFile; + + if (logFilePtr.i != nextAfterCurrentLogFilePtr.i) { + // This file should be closed. + logFilePtr.p->logFileStatus = LogFileRecord::CLOSE_SR_INVALIDATE_PAGES; + closeFile(signal, logFilePtr); + // Return from this function and wait for close confirm. Then come back + // and test the previous file for closing. + return; + } + } + + // We are done with closing files, send completed signal and exit this phase. + signal->theData[0] = ZSR_FOURTH_COMP; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; +} + + +/*---------------------------------------------------------------------------*/ +/* THE EXECUTION OF A LOG RECORD IS COMPLETED. RELEASE PAGES IF THEY WERE */ +/* READ FROM DISK FOR THIS PARTICULAR OPERATION. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::completedLab(Signal* signal) +{ + Uint32 result = returnExecLog(signal); +/*---------------------------------------------------------------------------*/ +/* ENTER COMPLETED WITH */ +/* LQH_CONNECTPTR */ +/*---------------------------------------------------------------------------*/ + if (result == ZOK) { + jam(); + execLogRecord(signal); + return; + } else if (result == ZNOT_OK) { + jam(); + signal->theData[0] = ZEXEC_SR; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + } else { + jam(); + /*empty*/; + }//if +/*---------------------------------------------------------------------------*/ +/* WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE PROCEEDING IN */ +/* RARE CASES. */ +/*---------------------------------------------------------------------------*/ + return; +}//Dblqh::completedLab() + +/*---------------------------------------------------------------------------*/ +/* EXECUTION OF LOG RECORD WAS NOT SUCCESSFUL. CHECK IF IT IS OK ANYWAY, */ +/* THEN EXECUTE THE NEXT LOG RECORD. */ +/*---------------------------------------------------------------------------*/ +void Dblqh::logLqhkeyrefLab(Signal* signal) +{ + Uint32 result = returnExecLog(signal); + switch (tcConnectptr.p->operation) { + case ZUPDATE: + case ZDELETE: + jam(); + ndbrequire(terrorCode == ZNO_TUPLE_FOUND); + break; + case ZINSERT: + jam(); + ndbrequire(terrorCode == ZTUPLE_ALREADY_EXIST); + break; + default: + ndbrequire(false); + return; + break; + }//switch + if (result == ZOK) { + jam(); + execLogRecord(signal); + return; + } else if (result == ZNOT_OK) { + jam(); + signal->theData[0] = ZEXEC_SR; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + } else { + jam(); + /*empty*/; + }//if + /* ------------------------------------------------------------------------ + * WE HAVE TO WAIT FOR CLOSING OF THE EXECUTED LOG FILE BEFORE + * PROCEEDING IN RARE CASES. + * ----------------------------------------------------------------------- */ + return; +}//Dblqh::logLqhkeyrefLab() + +void Dblqh::closeExecSrCompletedLab(Signal* signal) +{ + logFilePtr.p->logFileStatus = LogFileRecord::CLOSED; + signal->theData[0] = logFilePtr.p->logPartRec; + execLogComp(signal); + return; +}//Dblqh::closeExecSrCompletedLab() + +/* -------------------------------------------------------------------------- + * ONE OF THE LOG PARTS HAVE COMPLETED EXECUTING THE LOG. CHECK IF ALL LOG + * PARTS ARE COMPLETED. IF SO START SENDING EXEC_FRAGCONF AND EXEC_SRCONF. + * ------------------------------------------------------------------------- */ +void Dblqh::execLogComp(Signal* signal) +{ + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logPartPtr.p->logPartState = LogPartRecord::SR_THIRD_PHASE_COMPLETED; + /* ------------------------------------------------------------------------ + * WE MUST RELEASE THE TC CONNECT RECORD HERE SO THAT IT CAN BE REUSED. + * ----------------------------------------------------------------------- */ + tcConnectptr.i = logPartPtr.p->logTcConrec; + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + releaseTcrecLog(signal, tcConnectptr); + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_COMPLETED) { + if (logPartPtr.p->logPartState != LogPartRecord::SR_THIRD_PHASE_STARTED) { + jam(); + systemErrorLab(signal); + return; + } else { + jam(); + /* ------------------------------------------------------------------ + * THIS LOG PART WAS NOT COMPLETED YET. EXIT AND WAIT FOR IT + * TO COMPLETE + * ----------------------------------------------------------------- */ + return; + }//if + }//if + }//for + /* ------------------------------------------------------------------------ + * ALL LOG PARTS HAVE COMPLETED THE EXECUTION OF THE LOG. WE CAN NOW START + * SENDING THE EXEC_FRAGCONF SIGNALS TO ALL INVOLVED FRAGMENTS. + * ----------------------------------------------------------------------- */ + if (cstartType != NodeState::ST_NODE_RESTART) { + jam(); + signal->theData[0] = ZSEND_EXEC_CONF; + signal->theData[1] = 0; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + } else { + jam(); + /* ---------------------------------------------------------------------- + * FOR NODE RESTART WE CAN SKIP A NUMBER OF STEPS SINCE WE HAVE NO + * FRAGMENTS DEFINED AT THIS POINT. OBVIOUSLY WE WILL NOT NEED TO + * EXECUTE ANY MORE LOG STEPS EITHER AND THUS WE CAN IMMEDIATELY + * START FINDING THE END AND THE START OF THE LOG. + * --------------------------------------------------------------------- */ + csrPhasesCompleted = 3; + execSrCompletedLab(signal); + return; + }//if + return; +}//Dblqh::execLogComp() + +/* -------------------------------------------------------------------------- + * GO THROUGH THE FRAGMENT RECORDS TO DEDUCE TO WHICH SHALL BE SENT + * EXEC_FRAGCONF AFTER COMPLETING THE EXECUTION OF THE LOG. + * ------------------------------------------------------------------------- */ +void Dblqh::sendExecConf(Signal* signal) +{ + jamEntry(); + fragptr.i = signal->theData[0]; + Uint32 loopCount = 0; + while (fragptr.i < cfragrecFileSize) { + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + if (fragptr.p->execSrStatus != Fragrecord::IDLE) { + jam(); + ndbrequire(fragptr.p->execSrNoReplicas - 1 < 4); + for (Uint32 i = 0; i < fragptr.p->execSrNoReplicas; i++) { + jam(); + signal->theData[0] = fragptr.p->execSrUserptr[i]; + sendSignal(fragptr.p->execSrBlockref[i], GSN_EXEC_FRAGCONF, + signal, 1, JBB); + }//for + if (fragptr.p->execSrStatus == Fragrecord::ACTIVE) { + jam(); + fragptr.p->execSrStatus = Fragrecord::IDLE; + } else { + ndbrequire(fragptr.p->execSrStatus == Fragrecord::ACTIVE_REMOVE_AFTER); + jam(); + Uint32 fragId = fragptr.p->fragId; + tabptr.i = fragptr.p->tabRef; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + deleteFragrec(fragId); + }//if + fragptr.p->execSrNoReplicas = 0; + }//if + loopCount++; + if (loopCount > 20) { + jam(); + signal->theData[0] = ZSEND_EXEC_CONF; + signal->theData[1] = fragptr.i + 1; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + return; + } else { + jam(); + fragptr.i++; + }//if + }//while + /* ---------------------------------------------------------------------- + * WE HAVE NOW SENT ALL EXEC_FRAGCONF. NOW IT IS TIME TO SEND + * EXEC_SRCONF TO ALL NODES. + * --------------------------------------------------------------------- */ + srPhase3Comp(signal); +}//Dblqh::sendExecConf() + +/* -------------------------------------------------------------------------- + * PHASE 3 HAS NOW COMPLETED. INFORM ALL OTHER NODES OF THIS EVENT. + * ------------------------------------------------------------------------- */ +void Dblqh::srPhase3Comp(Signal* signal) +{ + jamEntry(); + ndbrequire(cnoOfNodes < MAX_NDB_NODES); + for (Uint32 i = 0; i < cnoOfNodes; i++) { + jam(); + if (cnodeStatus[i] == ZNODE_UP) { + jam(); + ndbrequire(cnodeData[i] < MAX_NDB_NODES); + BlockReference ref = calcLqhBlockRef(cnodeData[i]); + signal->theData[0] = cownNodeid; + sendSignal(ref, GSN_EXEC_SRCONF, signal, 1, JBB); + }//if + }//for + return; +}//Dblqh::srPhase3Comp() + +/* ########################################################################## + * SYSTEM RESTART PHASE FOUR MODULE + * THIS MODULE IS A SUB-MODULE OF THE FILE SYSTEM HANDLING. + * + * THIS MODULE SETS UP THE HEAD AND TAIL POINTERS OF THE LOG PARTS IN THE + * FRAGMENT LOG. WHEN IT IS COMPLETED IT REPORTS TO THE MASTER DIH THAT + * IT HAS COMPLETED THE PART OF THE SYSTEM RESTART WHERE THE DATABASE IS + * LOADED. + * IT ALSO OPENS THE CURRENT LOG FILE AND THE NEXT AND SETS UP THE FIRST + * LOG PAGE WHERE NEW LOG DATA IS TO BE INSERTED WHEN THE SYSTEM STARTS + * AGAIN. + * + * THIS PART IS ACTUALLY EXECUTED FOR ALL RESTART TYPES. + * ######################################################################### */ +void Dblqh::initFourth(Signal* signal) +{ + LogFileRecordPtr locLogFilePtr; + jamEntry(); + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + crestartNewestGci = 1; + crestartOldestGci = 1; + /* ------------------------------------------------------------------------ + * INITIALISE LOG PART AND LOG FILES AS NEEDED. + * ----------------------------------------------------------------------- */ + logPartPtr.p->headFileNo = 0; + logPartPtr.p->headPageNo = 1; + logPartPtr.p->headPageIndex = ZPAGE_HEADER_SIZE + 2; + logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_STARTED; + logPartPtr.p->logTailFileNo = 0; + logPartPtr.p->logTailMbyte = 0; + locLogFilePtr.i = logPartPtr.p->firstLogfile; + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_PHASE; + openFileRw(signal, locLogFilePtr); + return; +}//Dblqh::initFourth() + +void Dblqh::openSrFourthPhaseLab(Signal* signal) +{ + /* ------------------------------------------------------------------------ + * WE HAVE NOW OPENED THE HEAD LOG FILE WE WILL NOW START READING IT + * FROM THE HEAD MBYTE TO FIND THE NEW HEAD OF THE LOG. + * ----------------------------------------------------------------------- */ + readSinglePage(signal, logPartPtr.p->headPageNo); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_PHASE; + return; +}//Dblqh::openSrFourthPhaseLab() + +void Dblqh::readSrFourthPhaseLab(Signal* signal) +{ + if(c_diskless){ + jam(); + logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; + } + + /* ------------------------------------------------------------------------ + * INITIALISE ALL LOG PART INFO AND LOG FILE INFO THAT IS NEEDED TO + * START UP THE SYSTEM. + * ------------------------------------------------------------------------ + * INITIALISE THE NEWEST GLOBAL CHECKPOINT IDENTITY AND THE NEWEST + * COMPLETED GLOBAL CHECKPOINT IDENITY AS THE NEWEST THAT WAS RESTARTED. + * ------------------------------------------------------------------------ + * INITIALISE THE HEAD PAGE INDEX IN THIS PAGE. + * ASSIGN IT AS THE CURRENT LOGPAGE. + * ASSIGN THE FILE AS THE CURRENT LOG FILE. + * ASSIGN THE CURRENT FILE NUMBER FROM THE CURRENT LOG FILE AND THE NEXT + * FILE NUMBER FROM THE NEXT LOG FILE. + * ASSIGN THE CURRENT FILEPAGE FROM HEAD PAGE NUMBER. + * ASSIGN THE CURRENT MBYTE BY DIVIDING PAGE NUMBER BY 128. + * INITIALISE LOG LAP TO BE THE LOG LAP AS FOUND IN THE HEAD PAGE. + * WE HAVE TO CALCULATE THE NUMBER OF REMAINING WORDS IN THIS MBYTE. + * ----------------------------------------------------------------------- */ + cnewestGci = crestartNewestGci; + cnewestCompletedGci = crestartNewestGci; + logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; + logPartPtr.p->currentLogfile = logFilePtr.i; + logFilePtr.p->filePosition = logPartPtr.p->headPageNo; + logFilePtr.p->currentMbyte = + logPartPtr.p->headPageNo >> ZTWOLOG_NO_PAGES_IN_MBYTE; + logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; + logPartPtr.p->logLap = logPagePtr.p->logPageWord[ZPOS_LOG_LAP]; + logFilePtr.p->currentFilepage = logPartPtr.p->headPageNo; + logFilePtr.p->currentLogpage = logPagePtr.i; + + initLogpage(signal); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->headPageIndex; + logFilePtr.p->remainingWordsInMbyte = + (( + ((logFilePtr.p->currentMbyte + 1) * ZPAGES_IN_MBYTE) - + logFilePtr.p->currentFilepage) * + (ZPAGE_SIZE - ZPAGE_HEADER_SIZE)) - + (logPartPtr.p->headPageIndex - ZPAGE_HEADER_SIZE); + /* ------------------------------------------------------------------------ + * THE NEXT STEP IS TO OPEN THE NEXT LOG FILE (IF THERE IS ONE). + * ----------------------------------------------------------------------- */ + if (logFilePtr.p->nextLogFile != logFilePtr.i) { + LogFileRecordPtr locLogFilePtr; + jam(); + locLogFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + locLogFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_NEXT; + openFileRw(signal, locLogFilePtr); + } else { + jam(); + /* ---------------------------------------------------------------------- + * THIS CAN ONLY OCCUR IF WE HAVE ONLY ONE LOG FILE. THIS LOG FILE MUST + * BE LOG FILE ZERO AND THAT IS THE FILE WE CURRENTLY HAVE READ. + * THUS WE CAN CONTINUE IMMEDIATELY TO READ PAGE ZERO IN FILE ZERO. + * --------------------------------------------------------------------- */ + openSrFourthZeroSkipInitLab(signal); + return; + }//if + return; +}//Dblqh::readSrFourthPhaseLab() + +void Dblqh::openSrFourthNextLab(Signal* signal) +{ + /* ------------------------------------------------------------------------ + * WE MUST ALSO HAVE FILE 0 OPEN ALL THE TIME. + * ----------------------------------------------------------------------- */ + logFilePtr.i = logPartPtr.p->firstLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + if (logFilePtr.p->logFileStatus == LogFileRecord::OPEN) { + jam(); + openSrFourthZeroSkipInitLab(signal); + return; + } else { + jam(); + logFilePtr.p->logFileStatus = LogFileRecord::OPEN_SR_FOURTH_ZERO; + openFileRw(signal, logFilePtr); + }//if + return; +}//Dblqh::openSrFourthNextLab() + +void Dblqh::openSrFourthZeroLab(Signal* signal) +{ + openSrFourthZeroSkipInitLab(signal); + return; +}//Dblqh::openSrFourthZeroLab() + +void Dblqh::openSrFourthZeroSkipInitLab(Signal* signal) +{ + if (logFilePtr.i == logPartPtr.p->currentLogfile) { + if (logFilePtr.p->currentFilepage == 0) { + jam(); + /* ------------------------------------------------------------------- + * THE HEADER PAGE IN THE LOG IS PAGE ZERO IN FILE ZERO. + * THIS SHOULD NEVER OCCUR. + * ------------------------------------------------------------------- */ + systemErrorLab(signal); + return; + }//if + }//if + readSinglePage(signal, 0); + lfoPtr.p->lfoState = LogFileOperationRecord::READ_SR_FOURTH_ZERO; + return; +}//Dblqh::openSrFourthZeroSkipInitLab() + +void Dblqh::readSrFourthZeroLab(Signal* signal) +{ + logFilePtr.p->logPageZero = logPagePtr.i; + // -------------------------------------------------------------------- + // This is moved to invalidateLogAfterLastGCI(), RT453. + // signal->theData[0] = ZSR_FOURTH_COMP; + // signal->theData[1] = logPartPtr.i; + // sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + // -------------------------------------------------------------------- + + // Need to invalidate log pages after the head of the log. RT 453. EDTJAMO. + // Set the start of the invalidation. + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPartPtr.p->invalidateFileNo = logPartPtr.p->headFileNo; + logPartPtr.p->invalidatePageNo = logPartPtr.p->headPageNo; + + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG_INVALIDATE; + seizeLfo(signal); + initLfo(signal); + // The state here is a little confusing, but simulates that we return + // to invalidateLogAfterLastGCI() from an invalidate write and are ready + // to read a page from file. + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; + + invalidateLogAfterLastGCI(signal); + return; +}//Dblqh::readSrFourthZeroLab() + +/* -------------------------------------------------------------------------- + * ONE OF THE LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART. + * CHECK IF ALL LOG PARTS ARE COMPLETED. IF SO SEND START_RECCONF + * ------------------------------------------------------------------------- */ +void Dblqh::srFourthComp(Signal* signal) +{ + jamEntry(); + logPartPtr.i = signal->theData[0]; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logPartPtr.p->logPartState = LogPartRecord::SR_FOURTH_PHASE_COMPLETED; + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + jam(); + ptrAss(logPartPtr, logPartRecord); + if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_COMPLETED) { + if (logPartPtr.p->logPartState != LogPartRecord::SR_FOURTH_PHASE_STARTED) { + jam(); + systemErrorLab(signal); + return; + } else { + jam(); + /* ------------------------------------------------------------------ + * THIS LOG PART WAS NOT COMPLETED YET. + * EXIT AND WAIT FOR IT TO COMPLETE + * ----------------------------------------------------------------- */ + return; + }//if + }//if + }//for + /* ------------------------------------------------------------------------ + * ALL LOG PARTS HAVE COMPLETED PHASE FOUR OF THE SYSTEM RESTART. + * WE CAN NOW SEND START_RECCONF TO THE MASTER DIH IF IT WAS A + * SYSTEM RESTART. OTHERWISE WE WILL CONTINUE WITH AN INITIAL START. + * SET LOG PART STATE TO IDLE TO + * INDICATE THAT NOTHING IS GOING ON IN THE LOG PART. + * ----------------------------------------------------------------------- */ + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->logPartState = LogPartRecord::IDLE; + }//for + + if ((cstartType == NodeState::ST_INITIAL_START) || + (cstartType == NodeState::ST_INITIAL_NODE_RESTART)) { + jam(); + + ndbrequire(cinitialStartOngoing == ZTRUE); + cinitialStartOngoing = ZFALSE; + + checkStartCompletedLab(signal); + return; + } else if ((cstartType == NodeState::ST_NODE_RESTART) || + (cstartType == NodeState::ST_SYSTEM_RESTART)) { + jam(); + StartRecConf * conf = (StartRecConf*)signal->getDataPtrSend(); + conf->startingNodeId = getOwnNodeId(); + sendSignal(cmasterDihBlockref, GSN_START_RECCONF, signal, + StartRecConf::SignalLength, JBB); + + if(cstartType == NodeState::ST_SYSTEM_RESTART){ + fragptr.i = c_redo_log_complete_frags; + while(fragptr.i != RNIL){ + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + signal->theData[0] = fragptr.p->tabRef; + signal->theData[1] = fragptr.p->fragId; + sendSignal(DBACC_REF, GSN_EXPANDCHECK2, signal, 2, JBB); + fragptr.i = fragptr.p->nextFrag; + } + } + } else { + ndbrequire(false); + }//if + return; +}//Dblqh::srFourthComp() + +/* ######################################################################### */ +/* ####### ERROR MODULE ####### */ +/* */ +/* ######################################################################### */ +void Dblqh::warningHandlerLab(Signal* signal) +{ + systemErrorLab(signal); + return; +}//Dblqh::warningHandlerLab() + +/*---------------------------------------------------------------------------*/ +/* AN ERROR OCCURRED THAT WE WILL NOT TREAT AS SYSTEM ERROR. MOST OFTEN THIS */ +/* WAS CAUSED BY AN ERRONEUS SIGNAL SENT BY ANOTHER NODE. WE DO NOT WISH TO */ +/* CRASH BECAUSE OF FAULTS IN OTHER NODES. THUS WE ONLY REPORT A WARNING. */ +/* THIS IS CURRENTLY NOT IMPLEMENTED AND FOR THE MOMENT WE GENERATE A SYSTEM */ +/* ERROR SINCE WE WANT TO FIND FAULTS AS QUICKLY AS POSSIBLE IN A TEST PHASE.*/ +/* IN A LATER PHASE WE WILL CHANGE THIS TO BE A WARNING MESSAGE INSTEAD. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* THIS TYPE OF ERROR SHOULD NOT GENERATE A SYSTEM ERROR IN A PRODUCT */ +/* RELEASE. THIS IS A TEMPORARY SOLUTION DURING TEST PHASE TO QUICKLY */ +/* FIND ERRORS. NORMALLY THIS SHOULD GENERATE A WARNING MESSAGE ONTO */ +/* SOME ERROR LOGGER. THIS WILL LATER BE IMPLEMENTED BY SOME SIGNAL. */ +/*---------------------------------------------------------------------------*/ +/* ------ SYSTEM ERROR SITUATIONS ------- */ +/* IN SITUATIONS WHERE THE STATE IS ERRONEOUS OR IF THE ERROR OCCURS IN */ +/* THE COMMIT, COMPLETE OR ABORT PHASE, WE PERFORM A CRASH OF THE AXE VM*/ +/*---------------------------------------------------------------------------*/ + +void Dblqh::systemErrorLab(Signal* signal) +{ + progError(0, 0); +/*************************************************************************>*/ +/* WE WANT TO INVOKE AN IMMEDIATE ERROR HERE SO WE GET THAT BY */ +/* INSERTING A CERTAIN POINTER OUT OF RANGE. */ +/*************************************************************************>*/ +}//Dblqh::systemErrorLab() + +/* ------- ERROR SITUATIONS ------- */ + +void Dblqh::aiStateErrorCheckLab(Signal* signal, Uint32* dataPtr, Uint32 length) +{ + ndbrequire(tcConnectptr.p->abortState != TcConnectionrec::ABORT_IDLE); + if (tcConnectptr.p->transactionState != TcConnectionrec::IDLE) { + jam(); +/*************************************************************************>*/ +/* TRANSACTION ABORT IS ONGOING. IT CAN STILL BE A PART OF AN */ +/* OPERATION THAT SHOULD CONTINUE SINCE THE TUPLE HAS NOT ARRIVED */ +/* YET. THIS IS POSSIBLE IF ACTIVE CREATION OF THE FRAGMENT IS */ +/* ONGOING. */ +/*************************************************************************>*/ + if (tcConnectptr.p->activeCreat == ZTRUE) { + jam(); +/*************************************************************************>*/ +/* ONGOING ABORTS DURING ACTIVE CREATION MUST SAVE THE ATTRIBUTE INFO*/ +/* SO THAT IT CAN BE SENT TO THE NEXT NODE IN THE COMMIT CHAIN. THIS */ +/* IS NEEDED SINCE ALL ABORTS DURING CREATION OF A FRAGMENT ARE NOT */ +/* REALLY ERRORS. A MISSING TUPLE TO BE UPDATED SIMPLY MEANS THAT */ +/* IT HASN'T BEEN TRANSFERRED TO THE NEW REPLICA YET. */ +/*************************************************************************>*/ +/*************************************************************************>*/ +/* AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET */ +/* ACTIVE CREATION TO FALSE. THIS WILL ENSURE THAT THE ABORT IS */ +/* COMPLETED. */ +/*************************************************************************>*/ + if (saveTupattrbuf(signal, dataPtr, length) == ZOK) { + jam(); + if (tcConnectptr.p->transactionState == + TcConnectionrec::WAIT_AI_AFTER_ABORT) { + if (tcConnectptr.p->currTupAiLen == tcConnectptr.p->totReclenAi) { + jam(); +/*************************************************************************>*/ +/* WE WERE WAITING FOR MORE ATTRIBUTE INFO AFTER A SUCCESSFUL ABORT */ +/* IN ACTIVE CREATION STATE. THE TRANSACTION SHOULD CONTINUE AS IF */ +/* IT WAS COMMITTED. NOW ALL INFO HAS ARRIVED AND WE CAN CONTINUE */ +/* WITH NORMAL PROCESSING AS IF THE TRANSACTION WAS PREPARED. */ +/* SINCE THE FRAGMENT IS UNDER CREATION WE KNOW THAT LOGGING IS */ +/* DISABLED. WE STILL HAVE TO CATER FOR DIRTY OPERATION OR NOT. */ +/*************************************************************************>*/ + tcConnectptr.p->abortState = TcConnectionrec::ABORT_IDLE; + rwConcludedAiLab(signal); + return; + } else { + ndbrequire(tcConnectptr.p->currTupAiLen < tcConnectptr.p->totReclenAi); + jam(); + return; /* STILL WAITING FOR MORE ATTRIBUTE INFO */ + }//if + }//if + } else { + jam(); +/*************************************************************************>*/ +/* AFTER THIS ERROR THE ABORT MUST BE COMPLETED. TO ENSURE THIS SET */ +/* ACTIVE CREATION TO ABORT. THIS WILL ENSURE THAT THE ABORT IS */ +/* COMPLETED AND THAT THE ERROR CODE IS PROPERLY SET */ +/*************************************************************************>*/ + tcConnectptr.p->errorCode = terrorCode; + tcConnectptr.p->activeCreat = ZFALSE; + if (tcConnectptr.p->transactionState == + TcConnectionrec::WAIT_AI_AFTER_ABORT) { + jam(); +/*************************************************************************>*/ +/* ABORT IS ALREADY COMPLETED. WE NEED TO RESTART IT FROM WHERE IT */ +/* WAS INTERRUPTED. */ +/*************************************************************************>*/ + continueAbortLab(signal); + return; + } else { + jam(); + return; +/*************************************************************************>*/ +// Abort is ongoing. It will complete since we set the activeCreat = ZFALSE +/*************************************************************************>*/ + }//if + }//if + }//if + }//if +/*************************************************************************>*/ +/* TRANSACTION HAVE BEEN ABORTED. THUS IGNORE ALL SIGNALS BELONGING TO IT. */ +/*************************************************************************>*/ + return; +}//Dblqh::aiStateErrorCheckLab() + +void Dblqh::takeOverErrorLab(Signal* signal) +{ + terrorCode = ZTAKE_OVER_ERROR; + abortErrorLab(signal); + return; +}//Dblqh::takeOverErrorLab() + +/* ########################################################################## + * TEST MODULE + * ######################################################################### */ +#ifdef VM_TRACE +void Dblqh::execTESTSIG(Signal* signal) +{ + jamEntry(); + Uint32 userpointer = signal->theData[0]; + BlockReference userblockref = signal->theData[1]; + Uint32 testcase = signal->theData[2]; + + signal->theData[0] = userpointer; + signal->theData[1] = cownref; + signal->theData[2] = testcase; + sendSignal(userblockref, GSN_TESTSIG, signal, 25, JBB); + return; +}//Dblqh::execTESTSIG() + +/* *************** */ +/* MEMCHECKREQ > */ +/* *************** */ +/* ************************************************************************>> + * THIS SIGNAL IS PURELY FOR TESTING PURPOSES. IT CHECKS THE FREE LIST + * AND REPORTS THE NUMBER OF FREE RECORDS. + * THIS CAN BE DONE TO ENSURE THAT NO RECORDS HAS BEEN LOST + * ************************************************************************> */ +void Dblqh::execMEMCHECKREQ(Signal* signal) +{ + Uint32* dataPtr = &signal->theData[0]; + jamEntry(); + BlockReference userblockref = signal->theData[0]; + Uint32 index = 0; + for (Uint32 i = 0; i < 7; i++) + dataPtr[i] = 0; + addfragptr.i = cfirstfreeAddfragrec; + while (addfragptr.i != RNIL) { + ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); + addfragptr.i = addfragptr.p->nextAddfragrec; + dataPtr[index]++; + }//while + index++; + attrinbufptr.i = cfirstfreeAttrinbuf; + while (attrinbufptr.i != RNIL) { + ptrCheckGuard(attrinbufptr, cattrinbufFileSize, attrbuf); + attrinbufptr.i = attrinbufptr.p->attrbuf[ZINBUF_NEXT]; + dataPtr[index]++; + }//while + index++; + databufptr.i = cfirstfreeDatabuf; + while (databufptr.i != RNIL) { + ptrCheckGuard(databufptr, cdatabufFileSize, databuf); + databufptr.i = databufptr.p->nextDatabuf; + dataPtr[index]++; + }//while + index++; + fragptr.i = cfirstfreeFragrec; + while (fragptr.i != RNIL) { + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.i = fragptr.p->nextFrag; + dataPtr[index]++; + }//while + index++; + for (tabptr.i = 0; + tabptr.i < ctabrecFileSize; + tabptr.i++) { + ptrAss(tabptr, tablerec); + if (tabptr.p->tableStatus == Tablerec::NOT_DEFINED) { + dataPtr[index]++; + }//if + }//for + index++; + tcConnectptr.i = cfirstfreeTcConrec; + while (tcConnectptr.i != RNIL) { + ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + tcConnectptr.i = tcConnectptr.p->nextTcConnectrec; + dataPtr[index]++; + }//while + sendSignal(userblockref, GSN_MEMCHECKCONF, signal, 10, JBB); + return; +}//Dblqh::execMEMCHECKREQ() + +#endif + +/* ************************************************************************* */ +/* ************************* STATEMENT BLOCKS ****************************** */ +/* ************************************************************************* */ +/* ========================================================================= */ +/* ====== BUILD LINKED LIST OF LOG PAGES AFTER RECEIVING FSREADCONF ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::buildLinkedLogPageList(Signal* signal) +{ + LogPageRecordPtr bllLogPagePtr; + + arrGuard(lfoPtr.p->noPagesRw - 1, 16); + arrGuard(lfoPtr.p->noPagesRw, 16); + for (UintR tbllIndex = 0; tbllIndex < lfoPtr.p->noPagesRw; tbllIndex++) { + jam(); + /* ---------------------------------------------------------------------- + * BUILD LINKED LIST BUT ALSO ENSURE THAT PAGE IS NOT SEEN AS DIRTY + * INITIALLY. + * --------------------------------------------------------------------- */ + bllLogPagePtr.i = lfoPtr.p->logPageArray[tbllIndex]; + ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord); + +// #if VM_TRACE +// // Check logPage checksum before modifying it +// Uint32 calcCheckSum = calcPageCheckSum(bllLogPagePtr); +// Uint32 checkSum = bllLogPagePtr.p->logPageWord[ZPOS_CHECKSUM]; +// if (checkSum != calcCheckSum) { +// ndbout << "Redolog: Checksum failure." << endl; +// progError(__LINE__, ERR_NDBREQUIRE, "Redolog: Checksum failure."); +// } +// #endif + + bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] = + lfoPtr.p->logPageArray[tbllIndex + 1]; + bllLogPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; + }//for + bllLogPagePtr.i = lfoPtr.p->logPageArray[lfoPtr.p->noPagesRw - 1]; + ptrCheckGuard(bllLogPagePtr, clogPageFileSize, logPageRecord); + bllLogPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; +}//Dblqh::buildLinkedLogPageList() + +/* ========================================================================= + * ======= CHANGE TO NEXT MBYTE IN LOG ======= + * + * ========================================================================= */ +void Dblqh::changeMbyte(Signal* signal) +{ + writeNextLog(signal); + writeFileDescriptor(signal); +}//Dblqh::changeMbyte() + +/* ========================================================================= */ +/* ====== CHECK IF THIS COMMIT LOG RECORD IS TO BE EXECUTED ======= */ +/* */ +/* SUBROUTINE SHORT NAME = CEL */ +/* ========================================================================= */ +Uint32 Dblqh::checkIfExecLog(Signal* signal) +{ + tabptr.i = tcConnectptr.p->tableref; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + if (getFragmentrec(signal, tcConnectptr.p->fragmentid) && + (tabptr.p->schemaVersion == tcConnectptr.p->schemaVersion)) { + if (fragptr.p->execSrStatus != Fragrecord::IDLE) { + if (fragptr.p->execSrNoReplicas > logPartPtr.p->execSrExecuteIndex) { + ndbrequire((fragptr.p->execSrNoReplicas - 1) < 4); + for (Uint32 i = logPartPtr.p->execSrExecuteIndex; + i < fragptr.p->execSrNoReplicas; + i++) { + jam(); + if (tcConnectptr.p->gci >= fragptr.p->execSrStartGci[i]) { + if (tcConnectptr.p->gci <= fragptr.p->execSrLastGci[i]) { + jam(); + logPartPtr.p->execSrExecuteIndex = i; + return ZOK; + }//if + }//if + }//for + }//if + }//if + }//if + return ZNOT_OK; +}//Dblqh::checkIfExecLog() + +/* ========================================================================= */ +/* == CHECK IF THERE IS LESS THAN 192 KBYTE IN THE BUFFER PLUS INCOMING === */ +/* READS ALREADY STARTED. IF SO IS THE CASE THEN START ANOTHER READ IF */ +/* THERE ARE MORE PAGES IN THIS MBYTE. */ +/* */ +/* ========================================================================= */ +void Dblqh::checkReadExecSr(Signal* signal) +{ + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; + logPartPtr.p->execSrPagesRead = logPartPtr.p->execSrPagesRead + 8; + logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading - 8; + if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesReading) < + ZREAD_AHEAD_SIZE) { + jam(); + /* ---------------------------------------------------------------------- + * WE HAVE LESS THAN 64 KBYTE OF LOG PAGES REMAINING IN MEMORY OR ON + * ITS WAY TO MAIN MEMORY. READ IN 8 MORE PAGES. + * --------------------------------------------------------------------- */ + if ((logPartPtr.p->execSrPagesRead + logPartPtr.p->execSrPagesExecuted) < + ZPAGES_IN_MBYTE) { + jam(); + /* -------------------------------------------------------------------- + * THERE ARE MORE PAGES TO READ IN THIS MBYTE. READ THOSE FIRST + * IF >= ZPAGES_IN_MBYTE THEN THERE ARE NO MORE PAGES TO READ. THUS + * WE PROCEED WITH EXECUTION OF THE LOG. + * ------------------------------------------------------------------- */ + readExecSr(signal); + logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR; + }//if + }//if +}//Dblqh::checkReadExecSr() + +/* ========================================================================= */ +/* ==== CHECK IF START OF NEW FRAGMENT IS COMPLETED AND WE CAN ======= */ +/* ==== GET THE START GCI ======= */ +/* */ +/* SUBROUTINE SHORT NAME = CTC */ +/* ========================================================================= */ +void Dblqh::checkScanTcCompleted(Signal* signal) +{ + tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED; + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + fragptr.p->activeTcCounter = fragptr.p->activeTcCounter - 1; + if (fragptr.p->activeTcCounter == 0) { + jam(); + fragptr.p->startGci = cnewestGci + 1; + tabptr.i = tcConnectptr.p->tableref; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + sendCopyActiveConf(signal, tcConnectptr.p->tableref); + }//if +}//Dblqh::checkScanTcCompleted() + +/* ========================================================================== + * === CHECK IF ALL PARTS OF A SYSTEM RESTART ON A FRAGMENT ARE COMPLETED === + * + * SUBROUTINE SHORT NAME = CSC + * ========================================================================= */ +void Dblqh::checkSrCompleted(Signal* signal) +{ + LcpLocRecordPtr cscLcpLocptr; + + terrorCode = ZOK; + ptrGuard(lcpPtr); + cscLcpLocptr.i = lcpPtr.p->firstLcpLocAcc; +CSC_ACC_DOWHILE: + ptrCheckGuard(cscLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_COMPLETED) { + jam(); + if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_ACC_STARTED) { + jam(); + systemErrorLab(signal); + return; + }//if + return; + }//if + cscLcpLocptr.i = cscLcpLocptr.p->nextLcpLoc; + if (cscLcpLocptr.i != RNIL) { + jam(); + goto CSC_ACC_DOWHILE; + }//if + cscLcpLocptr.i = lcpPtr.p->firstLcpLocTup; +CSC_TUP_DOWHILE: + ptrCheckGuard(cscLcpLocptr, clcpLocrecFileSize, lcpLocRecord); + if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_TUP_COMPLETED) { + jam(); + if (cscLcpLocptr.p->lcpLocstate != LcpLocRecord::SR_TUP_STARTED) { + jam(); + systemErrorLab(signal); + return; + }//if + return; + }//if + cscLcpLocptr.i = cscLcpLocptr.p->nextLcpLoc; + if (cscLcpLocptr.i != RNIL) { + jam(); + goto CSC_TUP_DOWHILE; + }//if + lcpPtr.p->lcpState = LcpRecord::LCP_SR_COMPLETED; +}//Dblqh::checkSrCompleted() + +/* ------------------------------------------------------------------------- */ +/* ------ CLOSE A FILE DURING EXECUTION OF FRAGMENT LOG ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::closeFile(Signal* signal, LogFileRecordPtr clfLogFilePtr) +{ + signal->theData[0] = clfLogFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = clfLogFilePtr.i; + signal->theData[3] = ZCLOSE_NO_DELETE; + sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA); +}//Dblqh::closeFile() + + +/* ---------------------------------------------------------------- */ +/* ---------------- A LOG PAGE HAVE BEEN COMPLETED ---------------- */ +/* */ +/* SUBROUTINE SHORT NAME = CLP */ +// Input Pointers: +// logFilePtr +// logPagePtr +// logPartPtr +// Defines lfoPtr +/* ---------------------------------------------------------------- */ +void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) +{ + LogPageRecordPtr clpLogPagePtr; + LogPageRecordPtr wlpLogPagePtr; + UintR twlpNoPages; + UintR twlpType; + + if (logFilePtr.p->firstFilledPage == RNIL) { + jam(); + logFilePtr.p->firstFilledPage = logPagePtr.i; + } else { + jam(); + clpLogPagePtr.i = logFilePtr.p->lastFilledPage; + ptrCheckGuard(clpLogPagePtr, clogPageFileSize, logPageRecord); + clpLogPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i; + }//if + logFilePtr.p->lastFilledPage = logPagePtr.i; + logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + logFilePtr.p->noLogpagesInBuffer = logFilePtr.p->noLogpagesInBuffer + 1; + if (logFilePtr.p->noLogpagesInBuffer != ZMAX_PAGES_WRITTEN) { + if (clpType != ZLAST_WRITE_IN_FILE) { + if (clpType != ZENFORCE_WRITE) { + jam(); + return; + }//if + }//if + }//if + twlpType = clpType; +/* ------------------------------------------------------------------------- */ +/* ------ WRITE A SET OF LOG PAGES TO DISK ------- */ +/* */ +/* SUBROUTINE SHORT NAME: WLP */ +/* ------------------------------------------------------------------------- */ + seizeLfo(signal); + initLfo(signal); + Uint32* dataPtr = &signal->theData[6]; + twlpNoPages = 0; + wlpLogPagePtr.i = logFilePtr.p->firstFilledPage; + do { + dataPtr[twlpNoPages] = wlpLogPagePtr.i; + twlpNoPages++; + ptrCheckGuard(wlpLogPagePtr, clogPageFileSize, logPageRecord); + + // Calculate checksum for page + wlpLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(wlpLogPagePtr); + wlpLogPagePtr.i = wlpLogPagePtr.p->logPageWord[ZNEXT_PAGE]; + } while (wlpLogPagePtr.i != RNIL); + ndbrequire(twlpNoPages < 9); + dataPtr[twlpNoPages] = logFilePtr.p->filePosition; +/* -------------------------------------------------- */ +/* SET TIMER ON THIS LOG PART TO SIGNIFY THAT A */ +/* LOG RECORD HAS BEEN SENT AT THIS TIME. */ +/* -------------------------------------------------- */ + logPartPtr.p->logPartTimer = logPartPtr.p->logTimer; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + logFilePtr.p->logFilePagesToDiskWithoutSynch += twlpNoPages; + if (twlpType == ZLAST_WRITE_IN_FILE) { + jam(); + logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; + signal->theData[3] = ZLIST_OF_MEM_PAGES_SYNCH; + } else if (logFilePtr.p->logFilePagesToDiskWithoutSynch > + MAX_REDO_PAGES_WITHOUT_SYNCH) { + jam(); + logFilePtr.p->logFilePagesToDiskWithoutSynch = 0; + signal->theData[3] = ZLIST_OF_MEM_PAGES_SYNCH; + } else { + jam(); + signal->theData[3] = ZLIST_OF_MEM_PAGES; + }//if + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = twlpNoPages; + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 15, JBA); + if (twlpType == ZNORMAL) { + jam(); + lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; + } else if (twlpType == ZLAST_WRITE_IN_FILE) { + jam(); + lfoPtr.p->lfoState = LogFileOperationRecord::LAST_WRITE_IN_FILE; + } else { + ndbrequire(twlpType == ZENFORCE_WRITE); + jam(); + lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; + }//if + /* ----------------------------------------------------------------------- */ + /* ------ MOVE PAGES FROM LOG FILE TO LFO RECORD ------- */ + /* */ + /* ----------------------------------------------------------------------- */ + /* -------------------------------------------------- */ + /* MOVE PAGES TO LFO RECORD AND REMOVE THEM */ + /* FROM LOG FILE RECORD. */ + /* -------------------------------------------------- */ + lfoPtr.p->firstLfoPage = logFilePtr.p->firstFilledPage; + logFilePtr.p->firstFilledPage = RNIL; + logFilePtr.p->lastFilledPage = RNIL; + logFilePtr.p->noLogpagesInBuffer = 0; + + lfoPtr.p->noPagesRw = twlpNoPages; + lfoPtr.p->lfoPageNo = logFilePtr.p->filePosition; + lfoPtr.p->lfoWordWritten = ZPAGE_SIZE - 1; + logFilePtr.p->filePosition += twlpNoPages; +}//Dblqh::completedLogPage() + +/* ---------------------------------------------------------------- */ +/* ---------------- DELETE FRAGMENT RECORD ------------------------ */ +/* */ +/* SUBROUTINE SHORT NAME = DFR */ +/* ---------------------------------------------------------------- */ +void Dblqh::deleteFragrec(Uint32 fragId) +{ + Uint32 indexFound= RNIL; + fragptr.i = RNIL; + for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { + jam(); + if (tabptr.p->fragid[i] == fragId) { + fragptr.i = tabptr.p->fragrec[i]; + indexFound = i; + break; + }//if + }//for + if (fragptr.i != RNIL) { + jam(); + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + tabptr.p->fragid[indexFound] = ZNIL; + tabptr.p->fragrec[indexFound] = RNIL; + releaseFragrec(); + }//if +}//Dblqh::deleteFragrec() + +/* ------------------------------------------------------------------------- */ +/* ------- FIND LOG FILE RECORD GIVEN FILE NUMBER ------- */ +/* */ +/* INPUT: TFLF_FILE_NO THE FILE NUMBER */ +/* FLF_LOG_PART_PTR THE LOG PART RECORD */ +/* OUTPUT: FLF_LOG_FILE_PTR THE FOUND LOG FILE RECORD */ +/* SUBROUTINE SHORT NAME = FLF */ +/* ------------------------------------------------------------------------- */ +void Dblqh::findLogfile(Signal* signal, + Uint32 fileNo, + LogPartRecordPtr flfLogPartPtr, + LogFileRecordPtr* parLogFilePtr) +{ + LogFileRecordPtr locLogFilePtr; + locLogFilePtr.i = flfLogPartPtr.p->firstLogfile; + Uint32 loopCount = 0; + while (true) { + ptrCheckGuard(locLogFilePtr, clogFileFileSize, logFileRecord); + if (locLogFilePtr.p->fileNo == fileNo) { + jam(); + ndbrequire(loopCount == fileNo); + parLogFilePtr->i = locLogFilePtr.i; + parLogFilePtr->p = locLogFilePtr.p; + return; + }//if + locLogFilePtr.i = locLogFilePtr.p->nextLogFile; + loopCount++; + ndbrequire(loopCount < flfLogPartPtr.p->noLogFiles); + }//while +}//Dblqh::findLogfile() + +/* ------------------------------------------------------------------------- */ +/* ------ FIND PAGE REFERENCE IN MEMORY BUFFER AT LOG EXECUTION ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::findPageRef(Signal* signal, CommitLogRecord* commitLogRecord) +{ + UintR tfprIndex; + + logPagePtr.i = RNIL; + if (ERROR_INSERTED(5020)) { + // Force system to read page from disk + return; + } + pageRefPtr.i = logPartPtr.p->lastPageRef; + do { + ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); + if (commitLogRecord->fileNo == pageRefPtr.p->prFileNo) { + if (commitLogRecord->startPageNo >= pageRefPtr.p->prPageNo) { + if (commitLogRecord->startPageNo < (Uint16) (pageRefPtr.p->prPageNo + 8)) { + jam(); + tfprIndex = commitLogRecord->startPageNo - pageRefPtr.p->prPageNo; + logPagePtr.i = pageRefPtr.p->pageRef[tfprIndex]; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + return; + }//if + }//if + }//if + pageRefPtr.i = pageRefPtr.p->prPrev; + } while (pageRefPtr.i != RNIL); +}//Dblqh::findPageRef() + +/* ------------------------------------------------------------------------- */ +/* ------ GET FIRST OPERATION QUEUED FOR LOGGING ------- */ +/* */ +/* SUBROUTINE SHORT NAME = GFL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::getFirstInLogQueue(Signal* signal) +{ + TcConnectionrecPtr gflTcConnectptr; +/* -------------------------------------------------- */ +/* GET THE FIRST FROM THE LOG QUEUE AND REMOVE */ +/* IT FROM THE QUEUE. */ +/* -------------------------------------------------- */ + gflTcConnectptr.i = logPartPtr.p->firstLogQueue; + ptrCheckGuard(gflTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + logPartPtr.p->firstLogQueue = gflTcConnectptr.p->nextTcLogQueue; + if (logPartPtr.p->firstLogQueue == RNIL) { + jam(); + logPartPtr.p->lastLogQueue = RNIL; + }//if +}//Dblqh::getFirstInLogQueue() + +/* ---------------------------------------------------------------- */ +/* ---------------- GET FRAGMENT RECORD --------------------------- */ +/* INPUT: TFRAGID FRAGMENT ID LOOKING FOR */ +/* TABPTR TABLE ID */ +/* SUBROUTINE SHORT NAME = GFR */ +/* ---------------------------------------------------------------- */ +bool Dblqh::getFragmentrec(Signal* signal, Uint32 fragId) +{ + for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (UintR)~i; i--) { + jam(); + if (tabptr.p->fragid[i] == fragId) { + fragptr.i = tabptr.p->fragrec[i]; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + return true; + }//if + }//for + return false; +}//Dblqh::getFragmentrec() + +/* ========================================================================= */ +/* ====== INITIATE FRAGMENT RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseAddfragrec(Signal* signal) +{ + if (caddfragrecFileSize != 0) { + for (addfragptr.i = 0; addfragptr.i < caddfragrecFileSize; addfragptr.i++) { + ptrAss(addfragptr, addFragRecord); + addfragptr.p->addfragStatus = AddFragRecord::FREE; + addfragptr.p->nextAddfragrec = addfragptr.i + 1; + }//for + addfragptr.i = caddfragrecFileSize - 1; + ptrAss(addfragptr, addFragRecord); + addfragptr.p->nextAddfragrec = RNIL; + cfirstfreeAddfragrec = 0; + } else { + jam(); + cfirstfreeAddfragrec = RNIL; + }//if +}//Dblqh::initialiseAddfragrec() + +/* ========================================================================= */ +/* ====== INITIATE ATTRIBUTE IN AND OUT DATA BUFFER ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseAttrbuf(Signal* signal) +{ + if (cattrinbufFileSize != 0) { + for (attrinbufptr.i = 0; + attrinbufptr.i < cattrinbufFileSize; + attrinbufptr.i++) { + refresh_watch_dog(); + ptrAss(attrinbufptr, attrbuf); + attrinbufptr.p->attrbuf[ZINBUF_NEXT] = attrinbufptr.i + 1; + }//for + /* NEXT ATTRINBUF */ + attrinbufptr.i = cattrinbufFileSize - 1; + ptrAss(attrinbufptr, attrbuf); + attrinbufptr.p->attrbuf[ZINBUF_NEXT] = RNIL; /* NEXT ATTRINBUF */ + cfirstfreeAttrinbuf = 0; + } else { + jam(); + cfirstfreeAttrinbuf = RNIL; + }//if +}//Dblqh::initialiseAttrbuf() + +/* ========================================================================= */ +/* ====== INITIATE DATA BUFFER ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseDatabuf(Signal* signal) +{ + if (cdatabufFileSize != 0) { + for (databufptr.i = 0; databufptr.i < cdatabufFileSize; databufptr.i++) { + refresh_watch_dog(); + ptrAss(databufptr, databuf); + databufptr.p->nextDatabuf = databufptr.i + 1; + }//for + databufptr.i = cdatabufFileSize - 1; + ptrAss(databufptr, databuf); + databufptr.p->nextDatabuf = RNIL; + cfirstfreeDatabuf = 0; + } else { + jam(); + cfirstfreeDatabuf = RNIL; + }//if +}//Dblqh::initialiseDatabuf() + +/* ========================================================================= */ +/* ====== INITIATE FRAGMENT RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseFragrec(Signal* signal) +{ + if (cfragrecFileSize != 0) { + for (fragptr.i = 0; fragptr.i < cfragrecFileSize; fragptr.i++) { + refresh_watch_dog(); + ptrAss(fragptr, fragrecord); + fragptr.p->fragStatus = Fragrecord::FREE; + fragptr.p->fragActiveStatus = ZFALSE; + fragptr.p->execSrStatus = Fragrecord::IDLE; + fragptr.p->srStatus = Fragrecord::SS_IDLE; + fragptr.p->nextFrag = fragptr.i + 1; + }//for + fragptr.i = cfragrecFileSize - 1; + ptrAss(fragptr, fragrecord); + fragptr.p->nextFrag = RNIL; + cfirstfreeFragrec = 0; + } else { + jam(); + cfirstfreeFragrec = RNIL; + }//if +}//Dblqh::initialiseFragrec() + +/* ========================================================================= */ +/* ====== INITIATE FRAGMENT RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseGcprec(Signal* signal) +{ + UintR tigpIndex; + + if (cgcprecFileSize != 0) { + for (gcpPtr.i = 0; gcpPtr.i < cgcprecFileSize; gcpPtr.i++) { + ptrAss(gcpPtr, gcpRecord); + for (tigpIndex = 0; tigpIndex <= 3; tigpIndex++) { + gcpPtr.p->gcpLogPartState[tigpIndex] = ZIDLE; + gcpPtr.p->gcpSyncReady[tigpIndex] = ZFALSE; + }//for + }//for + }//if +}//Dblqh::initialiseGcprec() + +/* ========================================================================= */ +/* ====== INITIATE LCP RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseLcpRec(Signal* signal) +{ + if (clcpFileSize != 0) { + for (lcpPtr.i = 0; lcpPtr.i < clcpFileSize; lcpPtr.i++) { + ptrAss(lcpPtr, lcpRecord); + lcpPtr.p->lcpState = LcpRecord::LCP_IDLE; + lcpPtr.p->lcpQueued = false; + lcpPtr.p->firstLcpLocAcc = RNIL; + lcpPtr.p->firstLcpLocTup = RNIL; + lcpPtr.p->reportEmpty = false; + lcpPtr.p->lastFragmentFlag = false; + }//for + }//if +}//Dblqh::initialiseLcpRec() + +/* ========================================================================= */ +/* ====== INITIATE LCP LOCAL RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseLcpLocrec(Signal* signal) +{ + if (clcpLocrecFileSize != 0) { + for (lcpLocptr.i = 0; lcpLocptr.i < clcpLocrecFileSize; lcpLocptr.i++) { + ptrAss(lcpLocptr, lcpLocRecord); + lcpLocptr.p->nextLcpLoc = lcpLocptr.i + 1; + lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; + lcpLocptr.p->masterLcpRec = RNIL; + lcpLocptr.p->waitingBlock = LcpLocRecord::NONE; + }//for + lcpLocptr.i = clcpLocrecFileSize - 1; + ptrAss(lcpLocptr, lcpLocRecord); + lcpLocptr.p->nextLcpLoc = RNIL; + cfirstfreeLcpLoc = 0; + } else { + jam(); + cfirstfreeLcpLoc = RNIL; + }//if +}//Dblqh::initialiseLcpLocrec() + +/* ========================================================================= */ +/* ====== INITIATE LOG FILE OPERATION RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseLfo(Signal* signal) +{ + if (clfoFileSize != 0) { + for (lfoPtr.i = 0; lfoPtr.i < clfoFileSize; lfoPtr.i++) { + ptrAss(lfoPtr, logFileOperationRecord); + lfoPtr.p->lfoState = LogFileOperationRecord::IDLE; + lfoPtr.p->lfoTimer = 0; + lfoPtr.p->nextLfo = lfoPtr.i + 1; + }//for + lfoPtr.i = clfoFileSize - 1; + ptrAss(lfoPtr, logFileOperationRecord); + lfoPtr.p->nextLfo = RNIL; + cfirstfreeLfo = 0; + } else { + jam(); + cfirstfreeLfo = RNIL; + }//if +}//Dblqh::initialiseLfo() + +/* ========================================================================= */ +/* ====== INITIATE LOG FILE RECORD ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseLogFile(Signal* signal) +{ + if (clogFileFileSize != 0) { + for (logFilePtr.i = 0; logFilePtr.i < clogFileFileSize; logFilePtr.i++) { + ptrAss(logFilePtr, logFileRecord); + logFilePtr.p->nextLogFile = logFilePtr.i + 1; + logFilePtr.p->logFileStatus = LogFileRecord::LFS_IDLE; + }//for + logFilePtr.i = clogFileFileSize - 1; + ptrAss(logFilePtr, logFileRecord); + logFilePtr.p->nextLogFile = RNIL; + cfirstfreeLogFile = 0; + } else { + jam(); + cfirstfreeLogFile = RNIL; + }//if +}//Dblqh::initialiseLogFile() + +/* ========================================================================= */ +/* ====== INITIATE LOG PAGES ======= */ +/* */ +/* ========================================================================= */ +void Dblqh::initialiseLogPage(Signal* signal) +{ + if (clogPageFileSize != 0) { + for (logPagePtr.i = 0; logPagePtr.i < clogPageFileSize; logPagePtr.i++) { + refresh_watch_dog(); + ptrAss(logPagePtr, logPageRecord); + logPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i + 1; + }//for + logPagePtr.i = clogPageFileSize - 1; + ptrAss(logPagePtr, logPageRecord); + logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + cfirstfreeLogPage = 0; + } else { + jam(); + cfirstfreeLogPage = RNIL; + }//if + cnoOfLogPages = clogPageFileSize; +}//Dblqh::initialiseLogPage() + +/* ========================================================================= + * ====== INITIATE LOG PART RECORD ======= + * + * ========================================================================= */ +void Dblqh::initialiseLogPart(Signal* signal) +{ + for (logPartPtr.i = 0; logPartPtr.i <= 3; logPartPtr.i++) { + ptrAss(logPartPtr, logPartRecord); + logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; + logPartPtr.p->LogLqhKeyReqSent = ZFALSE; + logPartPtr.p->logPartNewestCompletedGCI = (UintR)-1; + }//for +}//Dblqh::initialiseLogPart() + +void Dblqh::initialisePageRef(Signal* signal) +{ + if (cpageRefFileSize != 0) { + for (pageRefPtr.i = 0; + pageRefPtr.i < cpageRefFileSize; + pageRefPtr.i++) { + ptrAss(pageRefPtr, pageRefRecord); + pageRefPtr.p->prNext = pageRefPtr.i + 1; + }//for + pageRefPtr.i = cpageRefFileSize - 1; + ptrAss(pageRefPtr, pageRefRecord); + pageRefPtr.p->prNext = RNIL; + cfirstfreePageRef = 0; + } else { + jam(); + cfirstfreePageRef = RNIL; + }//if +}//Dblqh::initialisePageRef() + +/* ========================================================================== + * ======= INITIATE RECORDS ======= + * + * TAKES CARE OF INITIATION OF ALL RECORDS IN THIS BLOCK. + * ========================================================================= */ +void Dblqh::initialiseRecordsLab(Signal* signal, Uint32 data, + Uint32 retRef, Uint32 retData) +{ + Uint32 i; + switch (data) { + case 0: + jam(); + for (i = 0; i < MAX_NDB_NODES; i++) { + cnodeSrState[i] = ZSTART_SR; + cnodeExecSrState[i] = ZSTART_SR; + }//for + for (i = 0; i < 1024; i++) { + ctransidHash[i] = RNIL; + }//for + for (i = 0; i < 4; i++) { + cactiveCopy[i] = RNIL; + }//for + cnoActiveCopy = 0; + cCounterAccCommitBlocked = 0; + cCounterTupCommitBlocked = 0; + caccCommitBlocked = false; + ctupCommitBlocked = false; + cCommitBlocked = false; + ccurrentGcprec = RNIL; + caddNodeState = ZFALSE; + cstartRecReq = ZFALSE; + cnewestGci = (UintR)-1; + cnewestCompletedGci = (UintR)-1; + crestartOldestGci = 0; + crestartNewestGci = 0; + cfirstWaitFragSr = RNIL; + cfirstCompletedFragSr = RNIL; + csrPhaseStarted = ZSR_NO_PHASE_STARTED; + csrPhasesCompleted = 0; + cmasterDihBlockref = 0; + cnoFragmentsExecSr = 0; + clcpCompletedState = LCP_IDLE; + csrExecUndoLogState = EULS_IDLE; + c_lcpId = 0; + cnoOfFragsCheckpointed = 0; + break; + case 1: + jam(); + initialiseAddfragrec(signal); + break; + case 2: + jam(); + initialiseAttrbuf(signal); + break; + case 3: + jam(); + initialiseDatabuf(signal); + break; + case 4: + jam(); + initialiseFragrec(signal); + break; + case 5: + jam(); + initialiseGcprec(signal); + initialiseLcpRec(signal); + initialiseLcpLocrec(signal); + break; + case 6: + jam(); + initialiseLogPage(signal); + break; + case 7: + jam(); + initialiseLfo(signal); + break; + case 8: + jam(); + initialiseLogFile(signal); + initialiseLogPart(signal); + break; + case 9: + jam(); + initialisePageRef(signal); + break; + case 10: + jam(); + initialiseScanrec(signal); + break; + case 11: + jam(); + initialiseTabrec(signal); + break; + case 12: + jam(); + initialiseTcNodeFailRec(signal); + initialiseTcrec(signal); + { + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = retData; + sendSignal(retRef, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); + } + return; + break; + default: + ndbrequire(false); + break; + }//switch + + signal->theData[0] = ZINITIALISE_RECORDS; + signal->theData[1] = data + 1; + signal->theData[2] = 0; + signal->theData[3] = retRef; + signal->theData[4] = retData; + sendSignal(DBLQH_REF, GSN_CONTINUEB, signal, 5, JBB); + + return; +}//Dblqh::initialiseRecordsLab() + +/* ========================================================================== + * ======= INITIATE TC CONNECTION RECORD ======= + * + * ========================================================================= */ +void Dblqh::initialiseScanrec(Signal* signal) +{ + ndbrequire(cscanrecFileSize > 1); + DLList<ScanRecord> tmp(c_scanRecordPool); + while (tmp.seize(scanptr)){ + //new (scanptr.p) ScanRecord(); + refresh_watch_dog(); + scanptr.p->scanType = ScanRecord::ST_IDLE; + scanptr.p->scanState = ScanRecord::SCAN_FREE; + scanptr.p->scanTcWaiting = ZFALSE; + scanptr.p->nextHash = RNIL; + scanptr.p->prevHash = RNIL; + scanptr.p->scan_acc_index= 0; + scanptr.p->scan_acc_attr_recs= 0; + } + tmp.release(); +}//Dblqh::initialiseScanrec() + +/* ========================================================================== + * ======= INITIATE TABLE RECORD ======= + * + * ========================================================================= */ +void Dblqh::initialiseTabrec(Signal* signal) +{ + if (ctabrecFileSize != 0) { + for (tabptr.i = 0; tabptr.i < ctabrecFileSize; tabptr.i++) { + refresh_watch_dog(); + ptrAss(tabptr, tablerec); + tabptr.p->tableStatus = Tablerec::NOT_DEFINED; + tabptr.p->usageCount = 0; + for (Uint32 i = 0; i <= (MAX_FRAG_PER_NODE - 1); i++) { + tabptr.p->fragid[i] = ZNIL; + tabptr.p->fragrec[i] = RNIL; + }//for + }//for + }//if +}//Dblqh::initialiseTabrec() + +/* ========================================================================== + * ======= INITIATE TC CONNECTION RECORD ======= + * + * ========================================================================= */ +void Dblqh::initialiseTcrec(Signal* signal) +{ + if (ctcConnectrecFileSize != 0) { + for (tcConnectptr.i = 0; + tcConnectptr.i < ctcConnectrecFileSize; + tcConnectptr.i++) { + refresh_watch_dog(); + ptrAss(tcConnectptr, tcConnectionrec); + tcConnectptr.p->transactionState = TcConnectionrec::TC_NOT_CONNECTED; + tcConnectptr.p->tcScanRec = RNIL; + tcConnectptr.p->logWriteState = TcConnectionrec::NOT_STARTED; + tcConnectptr.p->firstAttrinbuf = RNIL; + tcConnectptr.p->lastAttrinbuf = RNIL; + tcConnectptr.p->firstTupkeybuf = RNIL; + tcConnectptr.p->lastTupkeybuf = RNIL; + tcConnectptr.p->tcTimer = 0; + tcConnectptr.p->nextTcConnectrec = tcConnectptr.i + 1; + }//for + tcConnectptr.i = ctcConnectrecFileSize - 1; + ptrAss(tcConnectptr, tcConnectionrec); + tcConnectptr.p->nextTcConnectrec = RNIL; + cfirstfreeTcConrec = 0; + } else { + jam(); + cfirstfreeTcConrec = RNIL; + }//if +}//Dblqh::initialiseTcrec() + +/* ========================================================================== + * ======= INITIATE TC CONNECTION RECORD ======= + * + * ========================================================================= */ +void Dblqh::initialiseTcNodeFailRec(Signal* signal) +{ + if (ctcNodeFailrecFileSize != 0) { + for (tcNodeFailptr.i = 0; + tcNodeFailptr.i < ctcNodeFailrecFileSize; + tcNodeFailptr.i++) { + ptrAss(tcNodeFailptr, tcNodeFailRecord); + tcNodeFailptr.p->tcFailStatus = TcNodeFailRecord::TC_STATE_FALSE; + }//for + }//if +}//Dblqh::initialiseTcNodeFailRec() + +/* ========================================================================== + * ======= INITIATE FRAGMENT RECORD ======= + * + * SUBROUTINE SHORT NAME = IF + * ========================================================================= */ +void Dblqh::initFragrec(Signal* signal, + Uint32 tableId, + Uint32 fragId, + Uint32 copyType) +{ + new (fragptr.p) Fragrecord(); + fragptr.p->m_scanNumberMask.set(); // All is free + fragptr.p->accBlockref = caccBlockref; + fragptr.p->accBlockedList = RNIL; + fragptr.p->activeList = RNIL; + fragptr.p->firstWaitQueue = RNIL; + fragptr.p->lastWaitQueue = RNIL; + fragptr.p->fragStatus = Fragrecord::DEFINED; + fragptr.p->fragCopy = copyType; + fragptr.p->tupBlockref = ctupBlockref; + fragptr.p->tuxBlockref = ctuxBlockref; + fragptr.p->lcpRef = RNIL; + fragptr.p->logFlag = Fragrecord::STATE_TRUE; + fragptr.p->lcpFlag = Fragrecord::LCP_STATE_TRUE; + for (Uint32 i = 0; i < MAX_LCP_STORED; i++) { + fragptr.p->lcpId[i] = 0; + }//for + fragptr.p->maxGciCompletedInLcp = 0; + fragptr.p->maxGciInLcp = 0; + fragptr.p->copyFragState = ZIDLE; + fragptr.p->nextFrag = RNIL; + fragptr.p->newestGci = cnewestGci; + fragptr.p->nextLcp = 0; + fragptr.p->tabRef = tableId; + fragptr.p->fragId = fragId; + fragptr.p->srStatus = Fragrecord::SS_IDLE; + fragptr.p->execSrStatus = Fragrecord::IDLE; + fragptr.p->execSrNoReplicas = 0; + fragptr.p->fragDistributionKey = 0; + fragptr.p->activeTcCounter = 0; + fragptr.p->tableFragptr = RNIL; +}//Dblqh::initFragrec() + +/* ========================================================================== + * ======= INITIATE FRAGMENT RECORD FOR SYSTEM RESTART ======= + * + * SUBROUTINE SHORT NAME = IFS + * ========================================================================= */ +void Dblqh::initFragrecSr(Signal* signal) +{ + const StartFragReq * const startFragReq = (StartFragReq *)&signal->theData[0]; + Uint32 lcpNo = startFragReq->lcpNo; + Uint32 noOfLogNodes = startFragReq->noOfLogNodes; + ndbrequire(noOfLogNodes <= 4); + fragptr.p->fragStatus = Fragrecord::CRASH_RECOVERING; + fragptr.p->srBlockref = startFragReq->userRef; + fragptr.p->srUserptr = startFragReq->userPtr; + fragptr.p->srChkpnr = lcpNo; + if (lcpNo == (MAX_LCP_STORED - 1)) { + jam(); + fragptr.p->lcpId[lcpNo] = startFragReq->lcpId; + fragptr.p->nextLcp = 0; + } else if (lcpNo < (MAX_LCP_STORED - 1)) { + jam(); + fragptr.p->lcpId[lcpNo] = startFragReq->lcpId; + fragptr.p->nextLcp = lcpNo + 1; + } else { + ndbrequire(lcpNo == ZNIL); + jam(); + fragptr.p->nextLcp = 0; + }//if + fragptr.p->srNoLognodes = noOfLogNodes; + fragptr.p->logFlag = Fragrecord::STATE_FALSE; + fragptr.p->srStatus = Fragrecord::SS_IDLE; + if (noOfLogNodes > 0) { + jam(); + for (Uint32 i = 0; i < noOfLogNodes; i++) { + jam(); + fragptr.p->srStartGci[i] = startFragReq->startGci[i]; + fragptr.p->srLastGci[i] = startFragReq->lastGci[i]; + fragptr.p->srLqhLognode[i] = startFragReq->lqhLogNode[i]; + }//for + fragptr.p->newestGci = startFragReq->lastGci[noOfLogNodes - 1]; + } else { + fragptr.p->newestGci = cnewestGci; + }//if +}//Dblqh::initFragrecSr() + +/* ========================================================================== + * ======= INITIATE INFORMATION ABOUT GLOBAL CHECKPOINTS ======= + * IN LOG FILE RECORDS + * + * INPUT: LOG_FILE_PTR CURRENT LOG FILE + * TNO_FD_DESCRIPTORS THE NUMBER OF FILE DESCRIPTORS + * TO READ FROM THE LOG PAGE + * LOG_PAGE_PTR PAGE ZERO IN LOG FILE + * SUBROUTINE SHORT NAME = IGL + * ========================================================================= */ +void Dblqh::initGciInLogFileRec(Signal* signal, Uint32 noFdDescriptors) +{ + LogFileRecordPtr iglLogFilePtr; + UintR tiglLoop; + UintR tiglIndex; + + tiglLoop = 0; + iglLogFilePtr.i = logFilePtr.i; + iglLogFilePtr.p = logFilePtr.p; +IGL_LOOP: + for (tiglIndex = 0; tiglIndex <= ZNO_MBYTES_IN_FILE - 1; tiglIndex++) { + arrGuard(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex, ZPAGE_SIZE); + iglLogFilePtr.p->logMaxGciCompleted[tiglIndex] = + logPagePtr.p->logPageWord[((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; + arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + ZNO_MBYTES_IN_FILE) + + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex, ZPAGE_SIZE); + iglLogFilePtr.p->logMaxGciStarted[tiglIndex] = + logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + ZNO_MBYTES_IN_FILE) + + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; + arrGuard((((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (2 * ZNO_MBYTES_IN_FILE)) + (tiglLoop * ZFD_PART_SIZE)) + + tiglIndex, ZPAGE_SIZE); + iglLogFilePtr.p->logLastPrepRef[tiglIndex] = + logPagePtr.p->logPageWord[(((ZPAGE_HEADER_SIZE + ZFD_HEADER_SIZE) + + (2 * ZNO_MBYTES_IN_FILE)) + + (tiglLoop * ZFD_PART_SIZE)) + tiglIndex]; + }//for + tiglLoop = tiglLoop + 1; + if (tiglLoop < noFdDescriptors) { + jam(); + iglLogFilePtr.i = iglLogFilePtr.p->prevLogFile; + ptrCheckGuard(iglLogFilePtr, clogFileFileSize, logFileRecord); + goto IGL_LOOP; + }//if +}//Dblqh::initGciInLogFileRec() + +/* ========================================================================== + * ======= INITIATE LCP RECORD WHEN USED FOR SYSTEM RESTART ======= + * + * SUBROUTINE SHORT NAME = ILS + * ========================================================================= */ +void Dblqh::initLcpSr(Signal* signal, + Uint32 lcpNo, + Uint32 lcpId, + Uint32 tableId, + Uint32 fragId, + Uint32 fragPtr) +{ + lcpPtr.p->lcpQueued = false; + lcpPtr.p->currentFragment.fragPtrI = fragPtr; + lcpPtr.p->currentFragment.lcpFragOrd.lcpNo = lcpNo; + lcpPtr.p->currentFragment.lcpFragOrd.lcpId = lcpId; + lcpPtr.p->currentFragment.lcpFragOrd.tableId = tableId; + lcpPtr.p->currentFragment.lcpFragOrd.fragmentId = fragId; + lcpPtr.p->lcpState = LcpRecord::LCP_SR_WAIT_FRAGID; + lcpPtr.p->firstLcpLocAcc = RNIL; + lcpPtr.p->firstLcpLocTup = RNIL; + lcpPtr.p->lcpAccptr = RNIL; +}//Dblqh::initLcpSr() + +/* ========================================================================== + * ======= INITIATE LOG PART ======= + * + * ========================================================================= */ +void Dblqh::initLogpart(Signal* signal) +{ + logPartPtr.p->execSrLogPage = RNIL; + logPartPtr.p->execSrLogPageIndex = ZNIL; + logPartPtr.p->execSrExecuteIndex = 0; + logPartPtr.p->noLogFiles = cnoLogFiles; + logPartPtr.p->logLap = 0; + logPartPtr.p->logTailFileNo = 0; + logPartPtr.p->logTailMbyte = 0; + logPartPtr.p->lastMbyte = ZNIL; + logPartPtr.p->logPartState = LogPartRecord::SR_FIRST_PHASE; + logPartPtr.p->logExecState = LogPartRecord::LES_IDLE; + logPartPtr.p->firstLogTcrec = RNIL; + logPartPtr.p->lastLogTcrec = RNIL; + logPartPtr.p->firstLogQueue = RNIL; + logPartPtr.p->lastLogQueue = RNIL; + logPartPtr.p->gcprec = RNIL; + logPartPtr.p->firstPageRef = RNIL; + logPartPtr.p->lastPageRef = RNIL; + logPartPtr.p->headFileNo = ZNIL; + logPartPtr.p->headPageNo = ZNIL; + logPartPtr.p->headPageIndex = ZNIL; +}//Dblqh::initLogpart() + +/* ========================================================================== + * ======= INITIATE LOG POINTERS ======= + * + * ========================================================================= */ +void Dblqh::initLogPointers(Signal* signal) +{ + logPartPtr.i = tcConnectptr.p->hashValue & 3; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + logFilePtr.i = logPartPtr.p->currentLogfile; + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); +}//Dblqh::initLogPointers() + +/* ------------------------------------------------------------------------- */ +/* ------- INIT REQUEST INFO BEFORE EXECUTING A LOG RECORD ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::initReqinfoExecSr(Signal* signal) +{ + UintR Treqinfo = 0; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + LqhKeyReq::setKeyLen(Treqinfo, regTcPtr->primKeyLen); +/* ------------------------------------------------------------------------- */ +/* NUMBER OF BACKUPS AND STANDBYS ARE ZERO AND NEED NOT BE SET. */ +/* REPLICA TYPE IS CLEARED BY SEND_LQHKEYREQ. */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* SET LAST REPLICA NUMBER TO ZERO (BIT 10-11) */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* SET DIRTY FLAG */ +/* ------------------------------------------------------------------------- */ + LqhKeyReq::setDirtyFlag(Treqinfo, 1); +/* ------------------------------------------------------------------------- */ +/* SET SIMPLE TRANSACTION */ +/* ------------------------------------------------------------------------- */ + LqhKeyReq::setSimpleFlag(Treqinfo, 1); +/* ------------------------------------------------------------------------- */ +/* SET OPERATION TYPE AND LOCK MODE (NEVER READ OPERATION OR SCAN IN LOG) */ +/* ------------------------------------------------------------------------- */ + LqhKeyReq::setLockType(Treqinfo, regTcPtr->operation); + LqhKeyReq::setOperation(Treqinfo, regTcPtr->operation); + regTcPtr->reqinfo = Treqinfo; +/* ------------------------------------------------------------------------ */ +/* NO OF BACKUP IS SET TO ONE AND NUMBER OF STANDBY NODES IS SET TO ZERO. */ +/* THUS THE RECEIVING NODE WILL EXPECT THAT IT IS THE LAST NODE AND WILL */ +/* SEND COMPLETED AS THE RESPONSE SIGNAL SINCE DIRTY_OP BIT IS SET. */ +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------- */ +/* SET REPLICA TYPE TO PRIMARY AND NUMBER OF REPLICA TO ONE */ +/* ------------------------------------------------------------------------- */ + regTcPtr->lastReplicaNo = 0; + regTcPtr->apiVersionNo = 0; + regTcPtr->nextSeqNoReplica = 0; + regTcPtr->opExec = 0; + regTcPtr->storedProcId = ZNIL; + regTcPtr->readlenAi = 0; + regTcPtr->nodeAfterNext[0] = ZNIL; + regTcPtr->nodeAfterNext[1] = ZNIL; + regTcPtr->dirtyOp = ZFALSE; + regTcPtr->tcBlockref = cownref; +}//Dblqh::initReqinfoExecSr() + +/* -------------------------------------------------------------------------- + * ------- INSERT FRAGMENT ------- + * + * ------------------------------------------------------------------------- */ +bool Dblqh::insertFragrec(Signal* signal, Uint32 fragId) +{ + terrorCode = ZOK; + if (cfirstfreeFragrec == RNIL) { + jam(); + terrorCode = ZNO_FREE_FRAGMENTREC; + return false; + }//if + seizeFragmentrec(signal); + for (Uint32 i = (MAX_FRAG_PER_NODE - 1); (Uint32)~i; i--) { + jam(); + if (tabptr.p->fragid[i] == ZNIL) { + jam(); + tabptr.p->fragid[i] = fragId; + tabptr.p->fragrec[i] = fragptr.i; + return true; + }//if + }//for + terrorCode = ZTOO_MANY_FRAGMENTS; + return false; +}//Dblqh::insertFragrec() + +/* -------------------------------------------------------------------------- + * ------- LINK OPERATION IN ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME: LFQ +// Input Pointers: +// tcConnectptr +// fragptr +* ------------------------------------------------------------------------- */ +void Dblqh::linkFragQueue(Signal* signal) +{ + TcConnectionrecPtr lfqTcConnectptr; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + Fragrecord * const regFragPtr = fragptr.p; + Uint32 tcIndex = tcConnectptr.i; + + lfqTcConnectptr.i = regFragPtr->lastWaitQueue; + regTcPtr->nextTc = RNIL; + regFragPtr->lastWaitQueue = tcIndex; + regTcPtr->prevTc = lfqTcConnectptr.i; + ndbrequire(regTcPtr->listState == TcConnectionrec::NOT_IN_LIST); + regTcPtr->listState = TcConnectionrec::WAIT_QUEUE_LIST; + if (lfqTcConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(lfqTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + lfqTcConnectptr.p->nextTc = tcIndex; + } else { + regFragPtr->firstWaitQueue = tcIndex; + }//if + return; +}//Dblqh::linkFragQueue() + +/* ------------------------------------------------------------------------- + * ------- LINK OPERATION INTO WAITING FOR LOGGING ------- + * + * SUBROUTINE SHORT NAME = LWL +// Input Pointers: +// tcConnectptr +// logPartPtr + * ------------------------------------------------------------------------- */ +void Dblqh::linkWaitLog(Signal* signal, LogPartRecordPtr regLogPartPtr) +{ + TcConnectionrecPtr lwlTcConnectptr; + +/* -------------------------------------------------- */ +/* LINK ACTIVE OPERATION INTO QUEUE WAITING FOR */ +/* ACCESS TO THE LOG PART. */ +/* -------------------------------------------------- */ + lwlTcConnectptr.i = regLogPartPtr.p->lastLogQueue; + if (lwlTcConnectptr.i == RNIL) { + jam(); + regLogPartPtr.p->firstLogQueue = tcConnectptr.i; + } else { + jam(); + ptrCheckGuard(lwlTcConnectptr, ctcConnectrecFileSize, tcConnectionrec); + lwlTcConnectptr.p->nextTcLogQueue = tcConnectptr.i; + }//if + regLogPartPtr.p->lastLogQueue = tcConnectptr.i; + tcConnectptr.p->nextTcLogQueue = RNIL; + if (regLogPartPtr.p->LogLqhKeyReqSent == ZFALSE) { + jam(); + regLogPartPtr.p->LogLqhKeyReqSent = ZTRUE; + signal->theData[0] = ZLOG_LQHKEYREQ; + signal->theData[1] = regLogPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//if +}//Dblqh::linkWaitLog() + +/* -------------------------------------------------------------------------- + * ------- START THE NEXT OPERATION ON THIS LOG PART IF ANY ------- + * ------- OPERATIONS ARE QUEUED. ------- + * + * SUBROUTINE SHORT NAME = LNS +// Input Pointers: +// tcConnectptr +// logPartPtr + * ------------------------------------------------------------------------- */ +void Dblqh::logNextStart(Signal* signal) +{ + LogPartRecordPtr lnsLogPartPtr; + UintR tlnsStillWaiting; + LogPartRecord * const regLogPartPtr = logPartPtr.p; + + if ((regLogPartPtr->firstLogQueue == RNIL) && + (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) && + (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE)) { +// -------------------------------------------------------------------------- +// Optimised route for the common case +// -------------------------------------------------------------------------- + regLogPartPtr->logPartState = LogPartRecord::IDLE; + return; + }//if + if (regLogPartPtr->firstLogQueue != RNIL) { + jam(); + if (regLogPartPtr->LogLqhKeyReqSent == ZFALSE) { + jam(); + regLogPartPtr->LogLqhKeyReqSent = ZTRUE; + signal->theData[0] = ZLOG_LQHKEYREQ; + signal->theData[1] = logPartPtr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); + }//if + } else { + if (regLogPartPtr->logPartState == LogPartRecord::ACTIVE) { + jam(); + regLogPartPtr->logPartState = LogPartRecord::IDLE; + } else { + jam(); + }//if + }//if + if (regLogPartPtr->waitWriteGciLog != LogPartRecord::WWGL_TRUE) { + jam(); + return; + } else { + jam(); +/* -------------------------------------------------------------------------- + * A COMPLETE GCI LOG RECORD IS WAITING TO BE WRITTEN. WE GIVE THIS HIGHEST + * PRIORITY AND WRITE IT IMMEDIATELY. AFTER WRITING IT WE CHECK IF ANY MORE + * LOG PARTS ARE WAITING. IF NOT WE SEND A SIGNAL THAT INITIALISES THE GCP + * RECORD TO WAIT UNTIL ALL COMPLETE GCI LOG RECORDS HAVE REACHED TO DISK. + * -------------------------------------------------------------------------- */ + writeCompletedGciLog(signal); + logPartPtr.p->waitWriteGciLog = LogPartRecord::WWGL_FALSE; + tlnsStillWaiting = ZFALSE; + for (lnsLogPartPtr.i = 0; lnsLogPartPtr.i < 4; lnsLogPartPtr.i++) { + jam(); + ptrAss(lnsLogPartPtr, logPartRecord); + if (lnsLogPartPtr.p->waitWriteGciLog == LogPartRecord::WWGL_TRUE) { + jam(); + tlnsStillWaiting = ZTRUE; + }//if + }//for + if (tlnsStillWaiting == ZFALSE) { + jam(); + signal->theData[0] = ZINIT_GCP_REC; + sendSignal(cownref, GSN_CONTINUEB, signal, 1, JBB); + }//if + }//if +}//Dblqh::logNextStart() + +/* -------------------------------------------------------------------------- + * ------- MOVE PAGES FROM LFO RECORD TO PAGE REFERENCE RECORD ------- + * WILL ALWAYS MOVE 8 PAGES TO A PAGE REFERENCE RECORD. + * + * SUBROUTINE SHORT NAME = MPR + * ------------------------------------------------------------------------- */ +void Dblqh::moveToPageRef(Signal* signal) +{ + LogPageRecordPtr mprLogPagePtr; + PageRefRecordPtr mprPageRefPtr; + UintR tmprIndex; + +/* -------------------------------------------------------------------------- + * ------- INSERT PAGE REFERENCE RECORD ------- + * + * INPUT: LFO_PTR LOG FILE OPERATION RECORD + * LOG_PART_PTR LOG PART RECORD + * PAGE_REF_PTR THE PAGE REFERENCE RECORD TO BE INSERTED. + * ------------------------------------------------------------------------- */ + PageRefRecordPtr iprPageRefPtr; + + if ((logPartPtr.p->mmBufferSize + 8) >= ZMAX_MM_BUFFER_SIZE) { + jam(); + pageRefPtr.i = logPartPtr.p->firstPageRef; + ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); + releasePrPages(signal); + removePageRef(signal); + } else { + jam(); + logPartPtr.p->mmBufferSize = logPartPtr.p->mmBufferSize + 8; + }//if + seizePageRef(signal); + if (logPartPtr.p->firstPageRef == RNIL) { + jam(); + logPartPtr.p->firstPageRef = pageRefPtr.i; + } else { + jam(); + iprPageRefPtr.i = logPartPtr.p->lastPageRef; + ptrCheckGuard(iprPageRefPtr, cpageRefFileSize, pageRefRecord); + iprPageRefPtr.p->prNext = pageRefPtr.i; + }//if + pageRefPtr.p->prPrev = logPartPtr.p->lastPageRef; + logPartPtr.p->lastPageRef = pageRefPtr.i; + + pageRefPtr.p->prFileNo = logFilePtr.p->fileNo; + pageRefPtr.p->prPageNo = lfoPtr.p->lfoPageNo; + tmprIndex = 0; + mprLogPagePtr.i = lfoPtr.p->firstLfoPage; +MPR_LOOP: + arrGuard(tmprIndex, 8); + pageRefPtr.p->pageRef[tmprIndex] = mprLogPagePtr.i; + tmprIndex = tmprIndex + 1; + ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord); + mprLogPagePtr.i = mprLogPagePtr.p->logPageWord[ZNEXT_PAGE]; + if (mprLogPagePtr.i != RNIL) { + jam(); + goto MPR_LOOP; + }//if + mprPageRefPtr.i = pageRefPtr.p->prPrev; + if (mprPageRefPtr.i != RNIL) { + jam(); + ptrCheckGuard(mprPageRefPtr, cpageRefFileSize, pageRefRecord); + mprLogPagePtr.i = mprPageRefPtr.p->pageRef[7]; + ptrCheckGuard(mprLogPagePtr, clogPageFileSize, logPageRecord); + mprLogPagePtr.p->logPageWord[ZNEXT_PAGE] = pageRefPtr.p->pageRef[0]; + }//if +}//Dblqh::moveToPageRef() + +/* ------------------------------------------------------------------------- */ +/* ------- READ THE ATTRINFO FROM THE LOG ------- */ +/* */ +/* SUBROUTINE SHORT NAME = RA */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readAttrinfo(Signal* signal) +{ + Uint32 remainingLen = tcConnectptr.p->totSendlenAi; + if (remainingLen == 0) { + jam(); + tcConnectptr.p->reclenAiLqhkey = 0; + return; + }//if + Uint32 dataLen = remainingLen; + if (remainingLen > 5) + dataLen = 5; + readLogData(signal, dataLen, &tcConnectptr.p->firstAttrinfo[0]); + tcConnectptr.p->reclenAiLqhkey = dataLen; + remainingLen -= dataLen; + while (remainingLen > 0) { + jam(); + dataLen = remainingLen; + if (remainingLen > 22) + dataLen = 22; + seizeAttrinbuf(signal); + readLogData(signal, dataLen, &attrinbufptr.p->attrbuf[0]); + attrinbufptr.p->attrbuf[ZINBUF_DATA_LEN] = dataLen; + remainingLen -= dataLen; + }//while +}//Dblqh::readAttrinfo() + +/* ------------------------------------------------------------------------- */ +/* ------- READ COMMIT LOG ------- */ +/* */ +/* SUBROUTINE SHORT NAME = RCL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readCommitLog(Signal* signal, CommitLogRecord* commitLogRecord) +{ + Uint32 trclPageIndex = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + if ((trclPageIndex + (ZCOMMIT_LOG_SIZE - 1)) < ZPAGE_SIZE) { + jam(); + tcConnectptr.p->tableref = logPagePtr.p->logPageWord[trclPageIndex + 0]; + tcConnectptr.p->schemaVersion = logPagePtr.p->logPageWord[trclPageIndex + 1]; + tcConnectptr.p->fragmentid = logPagePtr.p->logPageWord[trclPageIndex + 2]; + commitLogRecord->fileNo = logPagePtr.p->logPageWord[trclPageIndex + 3]; + commitLogRecord->startPageNo = logPagePtr.p->logPageWord[trclPageIndex + 4]; + commitLogRecord->startPageIndex = logPagePtr.p->logPageWord[trclPageIndex + 5]; + commitLogRecord->stopPageNo = logPagePtr.p->logPageWord[trclPageIndex + 6]; + tcConnectptr.p->gci = logPagePtr.p->logPageWord[trclPageIndex + 7]; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = + (trclPageIndex + ZCOMMIT_LOG_SIZE) - 1; + } else { + jam(); + tcConnectptr.p->tableref = readLogword(signal); + tcConnectptr.p->schemaVersion = readLogword(signal); + tcConnectptr.p->fragmentid = readLogword(signal); + commitLogRecord->fileNo = readLogword(signal); + commitLogRecord->startPageNo = readLogword(signal); + commitLogRecord->startPageIndex = readLogword(signal); + commitLogRecord->stopPageNo = readLogword(signal); + tcConnectptr.p->gci = readLogword(signal); + }//if + tcConnectptr.p->transid[0] = logPartPtr.i + 65536; + tcConnectptr.p->transid[1] = (DBLQH << 20) + (cownNodeid << 8); +}//Dblqh::readCommitLog() + +/* ------------------------------------------------------------------------- */ +/* ------- READ LOG PAGES FROM DISK IN ORDER TO EXECUTE A LOG ------- */ +/* RECORD WHICH WAS NOT FOUND IN MAIN MEMORY. */ +/* */ +/* SUBROUTINE SHORT NAME = REL */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readExecLog(Signal* signal) +{ + UintR trelIndex; + UintR trelI; + + seizeLfo(signal); + initLfo(signal); + trelI = logPartPtr.p->execSrStopPageNo - logPartPtr.p->execSrStartPageNo; + arrGuard(trelI + 1, 16); + lfoPtr.p->logPageArray[trelI + 1] = logPartPtr.p->execSrStartPageNo; + for (trelIndex = logPartPtr.p->execSrStopPageNo; (trelIndex >= logPartPtr.p->execSrStartPageNo) && + (UintR)~trelIndex; trelIndex--) { + jam(); + seizeLogpage(signal); + arrGuard(trelI, 16); + lfoPtr.p->logPageArray[trelI] = logPagePtr.i; + trelI--; + }//for + lfoPtr.p->lfoPageNo = logPartPtr.p->execSrStartPageNo; + lfoPtr.p->noPagesRw = (logPartPtr.p->execSrStopPageNo - + logPartPtr.p->execSrStartPageNo) + 1; + lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0]; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + signal->theData[3] = ZLIST_OF_MEM_PAGES; // edtjamo TR509 //ZLIST_OF_PAIRS; + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = lfoPtr.p->noPagesRw; + signal->theData[6] = lfoPtr.p->logPageArray[0]; + signal->theData[7] = lfoPtr.p->logPageArray[1]; + signal->theData[8] = lfoPtr.p->logPageArray[2]; + signal->theData[9] = lfoPtr.p->logPageArray[3]; + signal->theData[10] = lfoPtr.p->logPageArray[4]; + signal->theData[11] = lfoPtr.p->logPageArray[5]; + signal->theData[12] = lfoPtr.p->logPageArray[6]; + signal->theData[13] = lfoPtr.p->logPageArray[7]; + signal->theData[14] = lfoPtr.p->logPageArray[8]; + signal->theData[15] = lfoPtr.p->logPageArray[9]; + sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 16, JBA); +}//Dblqh::readExecLog() + +/* ------------------------------------------------------------------------- */ +/* ------- READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG ------- */ +/* */ +/* SUBROUTINE SHORT NAME = RES */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readExecSrNewMbyte(Signal* signal) +{ + logFilePtr.p->currentFilepage = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE; + logFilePtr.p->filePosition = logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE; + logPartPtr.p->execSrPagesRead = 0; + logPartPtr.p->execSrPagesReading = 0; + logPartPtr.p->execSrPagesExecuted = 0; + readExecSr(signal); + logPartPtr.p->logExecState = LogPartRecord::LES_WAIT_READ_EXEC_SR_NEW_MBYTE; +}//Dblqh::readExecSrNewMbyte() + +/* ------------------------------------------------------------------------- */ +/* ------- READ 64 KBYTES WHEN EXECUTING THE FRAGMENT LOG ------- */ +/* */ +/* SUBROUTINE SHORT NAME = RES */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readExecSr(Signal* signal) +{ + UintR tresPageid; + UintR tresIndex; + + tresPageid = logFilePtr.p->filePosition; + seizeLfo(signal); + initLfo(signal); + for (tresIndex = 7; (UintR)~tresIndex; tresIndex--) { + jam(); +/* ------------------------------------------------------------------------- */ +/* GO BACKWARDS SINCE WE INSERT AT THE BEGINNING AND WE WANT THAT FIRST PAGE */ +/* SHALL BE FIRST AND LAST PAGE LAST. */ +/* ------------------------------------------------------------------------- */ + seizeLogpage(signal); + lfoPtr.p->logPageArray[tresIndex] = logPagePtr.i; + }//for + lfoPtr.p->lfoState = LogFileOperationRecord::READ_EXEC_SR; + lfoPtr.p->lfoPageNo = tresPageid; + logFilePtr.p->filePosition = logFilePtr.p->filePosition + 8; + logPartPtr.p->execSrPagesReading = logPartPtr.p->execSrPagesReading + 8; + lfoPtr.p->noPagesRw = 8; + lfoPtr.p->firstLfoPage = lfoPtr.p->logPageArray[0]; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + signal->theData[3] = ZLIST_OF_MEM_PAGES; + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = 8; + signal->theData[6] = lfoPtr.p->logPageArray[0]; + signal->theData[7] = lfoPtr.p->logPageArray[1]; + signal->theData[8] = lfoPtr.p->logPageArray[2]; + signal->theData[9] = lfoPtr.p->logPageArray[3]; + signal->theData[10] = lfoPtr.p->logPageArray[4]; + signal->theData[11] = lfoPtr.p->logPageArray[5]; + signal->theData[12] = lfoPtr.p->logPageArray[6]; + signal->theData[13] = lfoPtr.p->logPageArray[7]; + signal->theData[14] = tresPageid; + sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA); +}//Dblqh::readExecSr() + +/* ------------------------------------------------------------------------- */ +/* ------------ READ THE PRIMARY KEY FROM THE LOG ---------------- */ +/* */ +/* SUBROUTINE SHORT NAME = RK */ +/* --------------------------------------------------------------------------*/ +void Dblqh::readKey(Signal* signal) +{ + Uint32 remainingLen = tcConnectptr.p->primKeyLen; + ndbrequire(remainingLen != 0); + Uint32 dataLen = remainingLen; + if (remainingLen > 4) + dataLen = 4; + readLogData(signal, dataLen, &tcConnectptr.p->tupkeyData[0]); + remainingLen -= dataLen; + while (remainingLen > 0) { + jam(); + seizeTupkeybuf(signal); + dataLen = remainingLen; + if (dataLen > 4) + dataLen = 4; + readLogData(signal, dataLen, &databufptr.p->data[0]); + remainingLen -= dataLen; + }//while +}//Dblqh::readKey() + +/* ------------------------------------------------------------------------- */ +/* ------------ READ A NUMBER OF WORDS FROM LOG INTO CDATA ---------------- */ +/* */ +/* SUBROUTINE SHORT NAME = RLD */ +/* --------------------------------------------------------------------------*/ +void Dblqh::readLogData(Signal* signal, Uint32 noOfWords, Uint32* dataPtr) +{ + ndbrequire(noOfWords < 32); + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + if ((logPos + noOfWords) >= ZPAGE_SIZE) { + for (Uint32 i = 0; i < noOfWords; i++) + dataPtr[i] = readLogwordExec(signal); + } else { + MEMCOPY_NO_WORDS(dataPtr, &logPagePtr.p->logPageWord[logPos], noOfWords); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + noOfWords; + }//if +}//Dblqh::readLogData() + +/* ------------------------------------------------------------------------- */ +/* ------------ READ THE LOG HEADER OF A PREPARE LOG HEADER ---------------- */ +/* */ +/* SUBROUTINE SHORT NAME = RLH */ +/* --------------------------------------------------------------------------*/ +void Dblqh::readLogHeader(Signal* signal) +{ + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + if ((logPos + ZLOG_HEAD_SIZE) < ZPAGE_SIZE) { + jam(); + tcConnectptr.p->hashValue = logPagePtr.p->logPageWord[logPos + 2]; + tcConnectptr.p->operation = logPagePtr.p->logPageWord[logPos + 3]; + tcConnectptr.p->totSendlenAi = logPagePtr.p->logPageWord[logPos + 4]; + tcConnectptr.p->primKeyLen = logPagePtr.p->logPageWord[logPos + 5]; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + ZLOG_HEAD_SIZE; + } else { + jam(); + readLogwordExec(signal); /* IGNORE PREPARE LOG RECORD TYPE */ + readLogwordExec(signal); /* IGNORE LOG RECORD SIZE */ + tcConnectptr.p->hashValue = readLogwordExec(signal); + tcConnectptr.p->operation = readLogwordExec(signal); + tcConnectptr.p->totSendlenAi = readLogwordExec(signal); + tcConnectptr.p->primKeyLen = readLogwordExec(signal); + }//if +}//Dblqh::readLogHeader() + +/* ------------------------------------------------------------------------- */ +/* ------- READ A WORD FROM THE LOG ------- */ +/* */ +/* OUTPUT: TLOG_WORD */ +/* SUBROUTINE SHORT NAME = RLW */ +/* ------------------------------------------------------------------------- */ +Uint32 Dblqh::readLogword(Signal* signal) +{ + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + ndbrequire(logPos < ZPAGE_SIZE); + Uint32 logWord = logPagePtr.p->logPageWord[logPos]; + logPos++; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; + if (logPos >= ZPAGE_SIZE) { + jam(); + logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; + logFilePtr.p->currentLogpage = logPagePtr.i; + logFilePtr.p->currentFilepage++; + logPartPtr.p->execSrPagesRead--; + logPartPtr.p->execSrPagesExecuted++; + }//if + return logWord; +}//Dblqh::readLogword() + +/* ------------------------------------------------------------------------- */ +/* ------- READ A WORD FROM THE LOG WHEN EXECUTING A LOG RECORD ------- */ +/* */ +/* OUTPUT: TLOG_WORD */ +/* SUBROUTINE SHORT NAME = RWE */ +/* ------------------------------------------------------------------------- */ +Uint32 Dblqh::readLogwordExec(Signal* signal) +{ + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + ndbrequire(logPos < ZPAGE_SIZE); + Uint32 logWord = logPagePtr.p->logPageWord[logPos]; + logPos++; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos; + if (logPos >= ZPAGE_SIZE) { + jam(); + logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + if (logPagePtr.i != RNIL){ + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; + } else { + // Reading word at the last pos in the last page + // Don't step forward to next page! + jam(); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]++; + } + }//if + return logWord; +}//Dblqh::readLogwordExec() + +/* ------------------------------------------------------------------------- */ +/* ------- READ A SINGLE PAGE FROM THE LOG ------- */ +/* */ +/* INPUT: TRSP_PAGE_NO */ +/* SUBROUTINE SHORT NAME = RSP */ +/* ------------------------------------------------------------------------- */ +void Dblqh::readSinglePage(Signal* signal, Uint32 pageNo) +{ + seizeLfo(signal); + initLfo(signal); + seizeLogpage(signal); + lfoPtr.p->firstLfoPage = logPagePtr.i; + lfoPtr.p->lfoPageNo = pageNo; + lfoPtr.p->noPagesRw = 1; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + signal->theData[3] = ZLIST_OF_PAIRS; + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = 1; + signal->theData[6] = logPagePtr.i; + signal->theData[7] = pageNo; + sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); +}//Dblqh::readSinglePage() + +/* -------------------------------------------------------------------------- + * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME = RAC + * ------------------------------------------------------------------------- */ +void Dblqh::releaseAccList(Signal* signal) +{ + TcConnectionrecPtr racTcNextConnectptr; + TcConnectionrecPtr racTcPrevConnectptr; + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + racTcPrevConnectptr.i = tcConnectptr.p->prevTc; + racTcNextConnectptr.i = tcConnectptr.p->nextTc; + if (tcConnectptr.p->listState != TcConnectionrec::ACC_BLOCK_LIST) { + jam(); + systemError(signal); + }//if + tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; + if (racTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(racTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + racTcNextConnectptr.p->prevTc = racTcPrevConnectptr.i; + }//if + if (racTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(racTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + racTcPrevConnectptr.p->nextTc = tcConnectptr.p->nextTc; + } else { + jam(); + /* --------------------------------------------------------------------- + * OPERATION RECORD IS FIRST IN ACTIVE LIST + * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. + * --------------------------------------------------------------------- */ + fragptr.p->accBlockedList = racTcNextConnectptr.i; + }//if +}//Dblqh::releaseAccList() + +/* -------------------------------------------------------------------------- + * ------- REMOVE COPY FRAGMENT FROM ACTIVE COPY LIST ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releaseActiveCopy(Signal* signal) +{ + /* MUST BE 8 BIT */ + UintR tracFlag; + UintR tracIndex; + + tracFlag = ZFALSE; + for (tracIndex = 0; tracIndex < 4; tracIndex++) { + if (tracFlag == ZFALSE) { + jam(); + if (cactiveCopy[tracIndex] == fragptr.i) { + jam(); + tracFlag = ZTRUE; + }//if + } else { + if (tracIndex < 3) { + jam(); + cactiveCopy[tracIndex - 1] = cactiveCopy[tracIndex]; + } else { + jam(); + cactiveCopy[3] = RNIL; + }//if + }//if + }//for + ndbrequire(tracFlag == ZTRUE); + cnoActiveCopy--; +}//Dblqh::releaseActiveCopy() + +/* -------------------------------------------------------------------------- + * ------- RELEASE OPERATION FROM ACTIVE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME = RAL + * ------------------------------------------------------------------------- */ +void Dblqh::releaseActiveList(Signal* signal) +{ + TcConnectionrecPtr ralTcNextConnectptr; + TcConnectionrecPtr ralTcPrevConnectptr; + ralTcPrevConnectptr.i = tcConnectptr.p->prevTc; + ralTcNextConnectptr.i = tcConnectptr.p->nextTc; + ndbrequire(tcConnectptr.p->listState == TcConnectionrec::IN_ACTIVE_LIST); + tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; + if (ralTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(ralTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + ralTcNextConnectptr.p->prevTc = ralTcPrevConnectptr.i; + }//if + if (ralTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(ralTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + ralTcPrevConnectptr.p->nextTc = tcConnectptr.p->nextTc; + } else { + jam(); + /* ---------------------------------------------------------------------- + * OPERATION RECORD IS FIRST IN ACTIVE LIST + * THIS MEANS THAT THERE EXISTS NO PREVIOUS TC THAT NEEDS TO BE UPDATED. + * --------------------------------------------------------------------- */ + fragptr.p->activeList = ralTcNextConnectptr.i; + }//if +}//Dblqh::releaseActiveList() + +/* -------------------------------------------------------------------------- + * ------- RELEASE ADD FRAGMENT RECORD ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releaseAddfragrec(Signal* signal) +{ + addfragptr.p->addfragStatus = AddFragRecord::FREE; + addfragptr.p->nextAddfragrec = cfirstfreeAddfragrec; + cfirstfreeAddfragrec = addfragptr.i; +}//Dblqh::releaseAddfragrec() + +/* -------------------------------------------------------------------------- + * ------- RELEASE FRAGMENT RECORD ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releaseFragrec() +{ + fragptr.p->fragStatus = Fragrecord::FREE; + fragptr.p->nextFrag = cfirstfreeFragrec; + cfirstfreeFragrec = fragptr.i; +}//Dblqh::releaseFragrec() + +/* -------------------------------------------------------------------------- + * ------- RELEASE LCP LOCAL RECORD ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releaseLcpLoc(Signal* signal) +{ + lcpLocptr.p->lcpLocstate = LcpLocRecord::IDLE; + lcpLocptr.p->nextLcpLoc = cfirstfreeLcpLoc; + cfirstfreeLcpLoc = lcpLocptr.i; +}//Dblqh::releaseLcpLoc() + +/* -------------------------------------------------------------------------- + * ------- RELEASE A PAGE REFERENCE RECORD. ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releasePageRef(Signal* signal) +{ + pageRefPtr.p->prNext = cfirstfreePageRef; + cfirstfreePageRef = pageRefPtr.i; +}//Dblqh::releasePageRef() + +/* -------------------------------------------------------------------------- + * --- RELEASE ALL PAGES IN THE MM BUFFER AFTER EXECUTING THE LOG ON IT. ---- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releaseMmPages(Signal* signal) +{ +RMP_LOOP: + jam(); + pageRefPtr.i = logPartPtr.p->firstPageRef; + if (pageRefPtr.i != RNIL) { + jam(); + ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); + releasePrPages(signal); + removePageRef(signal); + goto RMP_LOOP; + }//if +}//Dblqh::releaseMmPages() + +/* -------------------------------------------------------------------------- + * ------- RELEASE A SET OF PAGES AFTER EXECUTING THE LOG ON IT. ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::releasePrPages(Signal* signal) +{ + UintR trppIndex; + + for (trppIndex = 0; trppIndex <= 7; trppIndex++) { + jam(); + logPagePtr.i = pageRefPtr.p->pageRef[trppIndex]; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + releaseLogpage(signal); + }//for +}//Dblqh::releasePrPages() + +/* -------------------------------------------------------------------------- + * ------- RELEASE OPERATION FROM WAIT QUEUE LIST ON FRAGMENT ------- + * + * SUBROUTINE SHORT NAME : RWA + * ------------------------------------------------------------------------- */ +void Dblqh::releaseWaitQueue(Signal* signal) +{ + TcConnectionrecPtr rwaTcNextConnectptr; + TcConnectionrecPtr rwaTcPrevConnectptr; + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + rwaTcPrevConnectptr.i = tcConnectptr.p->prevTc; + rwaTcNextConnectptr.i = tcConnectptr.p->nextTc; + if (tcConnectptr.p->listState != TcConnectionrec::WAIT_QUEUE_LIST) { + jam(); + systemError(signal); + }//if + tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST; + if (rwaTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rwaTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rwaTcNextConnectptr.p->prevTc = rwaTcPrevConnectptr.i; + } else { + jam(); + fragptr.p->lastWaitQueue = rwaTcPrevConnectptr.i; + }//if + if (rwaTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rwaTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rwaTcPrevConnectptr.p->nextTc = rwaTcNextConnectptr.i; + } else { + jam(); + fragptr.p->firstWaitQueue = rwaTcNextConnectptr.i; + }//if +}//Dblqh::releaseWaitQueue() + +/* -------------------------------------------------------------------------- + * ------- REMOVE OPERATION RECORD FROM LIST ON LOG PART OF NOT ------- + * COMPLETED OPERATIONS IN THE LOG. + * + * SUBROUTINE SHORT NAME = RLO + * ------------------------------------------------------------------------- */ +void Dblqh::removeLogTcrec(Signal* signal) +{ + TcConnectionrecPtr rloTcNextConnectptr; + TcConnectionrecPtr rloTcPrevConnectptr; + rloTcPrevConnectptr.i = tcConnectptr.p->prevLogTcrec; + rloTcNextConnectptr.i = tcConnectptr.p->nextLogTcrec; + if (rloTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i; + } else { + jam(); + logPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i; + }//if + if (rloTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i; + } else { + jam(); + logPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i; + }//if +}//Dblqh::removeLogTcrec() + +/* -------------------------------------------------------------------------- + * ------- REMOVE PAGE REFERENCE RECORD FROM LIST IN THIS LOG PART ------- + * + * SUBROUTINE SHORT NAME = RPR + * ------------------------------------------------------------------------- */ +void Dblqh::removePageRef(Signal* signal) +{ + PageRefRecordPtr rprPageRefPtr; + + pageRefPtr.i = logPartPtr.p->firstPageRef; + if (pageRefPtr.i != RNIL) { + jam(); + ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); + if (pageRefPtr.p->prNext == RNIL) { + jam(); + logPartPtr.p->lastPageRef = RNIL; + logPartPtr.p->firstPageRef = RNIL; + } else { + jam(); + logPartPtr.p->firstPageRef = pageRefPtr.p->prNext; + rprPageRefPtr.i = pageRefPtr.p->prNext; + ptrCheckGuard(rprPageRefPtr, cpageRefFileSize, pageRefRecord); + rprPageRefPtr.p->prPrev = RNIL; + }//if + releasePageRef(signal); + }//if +}//Dblqh::removePageRef() + +/* ------------------------------------------------------------------------- */ +/* ------- RETURN FROM EXECUTION OF LOG ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +Uint32 Dblqh::returnExecLog(Signal* signal) +{ + tcConnectptr.p->connectState = TcConnectionrec::CONNECTED; + initLogPointers(signal); + logPartPtr.p->execSrExecuteIndex++; + Uint32 result = checkIfExecLog(signal); + if (result == ZOK) { + jam(); +/* ------------------------------------------------------------------------- */ +/* THIS LOG RECORD WILL BE EXECUTED AGAIN TOWARDS ANOTHER NODE. */ +/* ------------------------------------------------------------------------- */ + logPagePtr.i = logPartPtr.p->execSrLogPage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = + logPartPtr.p->execSrLogPageIndex; + } else { + jam(); +/* ------------------------------------------------------------------------- */ +/* NO MORE EXECUTION OF THIS LOG RECORD. */ +/* ------------------------------------------------------------------------- */ + if (logPartPtr.p->logExecState == + LogPartRecord::LES_EXEC_LOGREC_FROM_FILE) { + jam(); +/* ------------------------------------------------------------------------- */ +/* THE LOG RECORD WAS READ FROM DISK. RELEASE ITS PAGES IMMEDIATELY. */ +/* ------------------------------------------------------------------------- */ + lfoPtr.i = logPartPtr.p->execSrLfoRec; + ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + releaseLfoPages(signal); + releaseLfo(signal); + logPartPtr.p->logExecState = LogPartRecord::LES_EXEC_LOG; + if (logPartPtr.p->execSrExecLogFile != logPartPtr.p->currentLogfile) { + jam(); + LogFileRecordPtr clfLogFilePtr; + clfLogFilePtr.i = logPartPtr.p->execSrExecLogFile; + ptrCheckGuard(clfLogFilePtr, clogFileFileSize, logFileRecord); + clfLogFilePtr.p->logFileStatus = LogFileRecord::CLOSING_EXEC_LOG; + closeFile(signal, clfLogFilePtr); + result = ZCLOSE_FILE; + }//if + }//if + logPartPtr.p->execSrExecuteIndex = 0; + logPartPtr.p->execSrLogPage = RNIL; + logPartPtr.p->execSrLogPageIndex = ZNIL; + logPagePtr.i = logFilePtr.p->currentLogpage; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPartPtr.p->savePageIndex; + }//if + return result; +}//Dblqh::returnExecLog() + +/* -------------------------------------------------------------------------- + * ------- SEIZE ADD FRAGMENT RECORD ------ + * + * ------------------------------------------------------------------------- */ +void Dblqh::seizeAddfragrec(Signal* signal) +{ + addfragptr.i = cfirstfreeAddfragrec; + ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); + cfirstfreeAddfragrec = addfragptr.p->nextAddfragrec; +}//Dblqh::seizeAddfragrec() + +/* -------------------------------------------------------------------------- + * ------- SEIZE FRAGMENT RECORD ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::seizeFragmentrec(Signal* signal) +{ + fragptr.i = cfirstfreeFragrec; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + cfirstfreeFragrec = fragptr.p->nextFrag; + fragptr.p->nextFrag = RNIL; +}//Dblqh::seizeFragmentrec() + +/* ------------------------------------------------------------------------- */ +/* ------- SEIZE A PAGE REFERENCE RECORD. ------- */ +/* */ +/* ------------------------------------------------------------------------- */ +void Dblqh::seizePageRef(Signal* signal) +{ + pageRefPtr.i = cfirstfreePageRef; + ptrCheckGuard(pageRefPtr, cpageRefFileSize, pageRefRecord); + cfirstfreePageRef = pageRefPtr.p->prNext; + pageRefPtr.p->prNext = RNIL; +}//Dblqh::seizePageRef() + +/* -------------------------------------------------------------------------- + * ------- SEND ABORTED ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::sendAborted(Signal* signal) +{ + UintR TlastInd; + if (tcConnectptr.p->nextReplica == ZNIL) { + TlastInd = ZTRUE; + } else { + TlastInd = ZFALSE; + }//if + signal->theData[0] = tcConnectptr.p->tcOprec; + signal->theData[1] = tcConnectptr.p->transid[0]; + signal->theData[2] = tcConnectptr.p->transid[1]; + signal->theData[3] = cownNodeid; + signal->theData[4] = TlastInd; + sendSignal(tcConnectptr.p->tcBlockref, GSN_ABORTED, signal, 5, JBB); + return; +}//Dblqh::sendAborted() + +/* -------------------------------------------------------------------------- + * ------- SEND LQH_TRANSCONF ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::sendLqhTransconf(Signal* signal, LqhTransConf::OperationStatus stat) +{ + tcNodeFailptr.i = tcConnectptr.p->tcNodeFailrec; + ptrCheckGuard(tcNodeFailptr, ctcNodeFailrecFileSize, tcNodeFailRecord); + + Uint32 reqInfo = 0; + LqhTransConf::setReplicaType(reqInfo, tcConnectptr.p->replicaType); + LqhTransConf::setReplicaNo(reqInfo, tcConnectptr.p->seqNoReplica); + LqhTransConf::setLastReplicaNo(reqInfo, tcConnectptr.p->lastReplicaNo); + LqhTransConf::setSimpleFlag(reqInfo, tcConnectptr.p->opSimple); + LqhTransConf::setDirtyFlag(reqInfo, tcConnectptr.p->dirtyOp); + LqhTransConf::setOperation(reqInfo, tcConnectptr.p->operation); + + LqhTransConf * const lqhTransConf = (LqhTransConf *)&signal->theData[0]; + lqhTransConf->tcRef = tcNodeFailptr.p->newTcRef; + lqhTransConf->lqhNodeId = cownNodeid; + lqhTransConf->operationStatus = stat; + lqhTransConf->lqhConnectPtr = tcConnectptr.i; + lqhTransConf->transId1 = tcConnectptr.p->transid[0]; + lqhTransConf->transId2 = tcConnectptr.p->transid[1]; + lqhTransConf->oldTcOpRec = tcConnectptr.p->tcOprec; + lqhTransConf->requestInfo = reqInfo; + lqhTransConf->gci = tcConnectptr.p->gci; + lqhTransConf->nextNodeId1 = tcConnectptr.p->nextReplica; + lqhTransConf->nextNodeId2 = tcConnectptr.p->nodeAfterNext[0]; + lqhTransConf->nextNodeId3 = tcConnectptr.p->nodeAfterNext[1]; + lqhTransConf->apiRef = tcConnectptr.p->applRef; + lqhTransConf->apiOpRec = tcConnectptr.p->applOprec; + lqhTransConf->tableId = tcConnectptr.p->tableref; + sendSignal(tcNodeFailptr.p->newTcBlockref, GSN_LQH_TRANSCONF, + signal, LqhTransConf::SignalLength, JBB); + tcNodeFailptr.p->tcRecNow = tcConnectptr.i + 1; + signal->theData[0] = ZLQH_TRANS_NEXT; + signal->theData[1] = tcNodeFailptr.i; + sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); +}//Dblqh::sendLqhTransconf() + +/* -------------------------------------------------------------------------- + * ------- START ANOTHER PHASE OF LOG EXECUTION ------- + * RESET THE VARIABLES NEEDED BY THIS PROCESS AND SEND THE START SIGNAL + * + * ------------------------------------------------------------------------- */ +void Dblqh::startExecSr(Signal* signal) +{ + cnoFragmentsExecSr = 0; + signal->theData[0] = cfirstCompletedFragSr; + signal->theData[1] = RNIL; + sendSignal(cownref, GSN_START_EXEC_SR, signal, 2, JBB); +}//Dblqh::startExecSr() + +/* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ + * ¤¤¤¤¤¤¤ LOG MODULE ¤¤¤¤¤¤¤ + * ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */ +/* -------------------------------------------------------------------------- + * ------- STEP FORWARD IN FRAGMENT LOG DURING LOG EXECUTION ------- + * + * ------------------------------------------------------------------------- */ +void Dblqh::stepAhead(Signal* signal, Uint32 stepAheadWords) +{ + UintR tsaPos; + + tsaPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + while ((stepAheadWords + tsaPos) >= ZPAGE_SIZE) { + jam(); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_SIZE; + stepAheadWords = stepAheadWords - (ZPAGE_SIZE - tsaPos); + logFilePtr.p->currentLogpage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + logPagePtr.i = logPagePtr.p->logPageWord[ZNEXT_PAGE]; + logFilePtr.p->currentFilepage++; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = ZPAGE_HEADER_SIZE; + logPartPtr.p->execSrPagesRead--; + logPartPtr.p->execSrPagesExecuted++; + tsaPos = ZPAGE_HEADER_SIZE; + }//while + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = stepAheadWords + tsaPos; +}//Dblqh::stepAhead() + +/* -------------------------------------------------------------------------- + * ------- WRITE A ABORT LOG RECORD ------- + * + * SUBROUTINE SHORT NAME: WAL + * ------------------------------------------------------------------------- */ +void Dblqh::writeAbortLog(Signal* signal) +{ + if ((ZABORT_LOG_SIZE + ZNEXT_LOG_SIZE) > + logFilePtr.p->remainingWordsInMbyte) { + jam(); + changeMbyte(signal); + }//if + logFilePtr.p->remainingWordsInMbyte = + logFilePtr.p->remainingWordsInMbyte - ZABORT_LOG_SIZE; + writeLogWord(signal, ZABORT_TYPE); + writeLogWord(signal, tcConnectptr.p->transid[0]); + writeLogWord(signal, tcConnectptr.p->transid[1]); +}//Dblqh::writeAbortLog() + +/* -------------------------------------------------------------------------- + * ------- WRITE A COMMIT LOG RECORD ------- + * + * SUBROUTINE SHORT NAME: WCL + * ------------------------------------------------------------------------- */ +void Dblqh::writeCommitLog(Signal* signal, LogPartRecordPtr regLogPartPtr) +{ + LogFileRecordPtr regLogFilePtr; + LogPageRecordPtr regLogPagePtr; + TcConnectionrec * const regTcPtr = tcConnectptr.p; + regLogFilePtr.i = regLogPartPtr.p->currentLogfile; + ptrCheckGuard(regLogFilePtr, clogFileFileSize, logFileRecord); + regLogPagePtr.i = regLogFilePtr.p->currentLogpage; + Uint32 twclTmp = regLogFilePtr.p->remainingWordsInMbyte; + ptrCheckGuard(regLogPagePtr, clogPageFileSize, logPageRecord); + logPartPtr = regLogPartPtr; + logFilePtr = regLogFilePtr; + logPagePtr = regLogPagePtr; + if ((ZCOMMIT_LOG_SIZE + ZNEXT_LOG_SIZE) > twclTmp) { + jam(); + changeMbyte(signal); + twclTmp = logFilePtr.p->remainingWordsInMbyte; + }//if + + Uint32 twclLogPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + Uint32 tableId = regTcPtr->tableref; + Uint32 schemaVersion = regTcPtr->schemaVersion; + Uint32 fragId = regTcPtr->fragmentid; + Uint32 fileNo = regTcPtr->logStartFileNo; + Uint32 startPageNo = regTcPtr->logStartPageNo; + Uint32 pageIndex = regTcPtr->logStartPageIndex; + Uint32 stopPageNo = regTcPtr->logStopPageNo; + Uint32 gci = regTcPtr->gci; + logFilePtr.p->remainingWordsInMbyte = twclTmp - ZCOMMIT_LOG_SIZE; + + if ((twclLogPos + ZCOMMIT_LOG_SIZE) >= ZPAGE_SIZE) { + writeLogWord(signal, ZCOMMIT_TYPE); + writeLogWord(signal, tableId); + writeLogWord(signal, schemaVersion); + writeLogWord(signal, fragId); + writeLogWord(signal, fileNo); + writeLogWord(signal, startPageNo); + writeLogWord(signal, pageIndex); + writeLogWord(signal, stopPageNo); + writeLogWord(signal, gci); + } else { + Uint32* dataPtr = &logPagePtr.p->logPageWord[twclLogPos]; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = twclLogPos + ZCOMMIT_LOG_SIZE; + dataPtr[0] = ZCOMMIT_TYPE; + dataPtr[1] = tableId; + dataPtr[2] = schemaVersion; + dataPtr[3] = fragId; + dataPtr[4] = fileNo; + dataPtr[5] = startPageNo; + dataPtr[6] = pageIndex; + dataPtr[7] = stopPageNo; + dataPtr[8] = gci; + }//if + TcConnectionrecPtr rloTcNextConnectptr; + TcConnectionrecPtr rloTcPrevConnectptr; + rloTcPrevConnectptr.i = regTcPtr->prevLogTcrec; + rloTcNextConnectptr.i = regTcPtr->nextLogTcrec; + if (rloTcNextConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rloTcNextConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rloTcNextConnectptr.p->prevLogTcrec = rloTcPrevConnectptr.i; + } else { + regLogPartPtr.p->lastLogTcrec = rloTcPrevConnectptr.i; + }//if + if (rloTcPrevConnectptr.i != RNIL) { + jam(); + ptrCheckGuard(rloTcPrevConnectptr, ctcConnectrecFileSize, tcConnectionrec); + rloTcPrevConnectptr.p->nextLogTcrec = rloTcNextConnectptr.i; + } else { + regLogPartPtr.p->firstLogTcrec = rloTcNextConnectptr.i; + }//if +}//Dblqh::writeCommitLog() + +/* -------------------------------------------------------------------------- + * ------- WRITE A COMPLETED GCI LOG RECORD ------- + * + * SUBROUTINE SHORT NAME: WCG +// Input Pointers: +// logFilePtr +// logPartPtr + * ------------------------------------------------------------------------- */ +void Dblqh::writeCompletedGciLog(Signal* signal) +{ + if ((ZCOMPLETED_GCI_LOG_SIZE + ZNEXT_LOG_SIZE) > + logFilePtr.p->remainingWordsInMbyte) { + jam(); + changeMbyte(signal); + }//if + logFilePtr.p->remainingWordsInMbyte = + logFilePtr.p->remainingWordsInMbyte - ZCOMPLETED_GCI_LOG_SIZE; + writeLogWord(signal, ZCOMPLETED_GCI_TYPE); + writeLogWord(signal, cnewestCompletedGci); + logPartPtr.p->logPartNewestCompletedGCI = cnewestCompletedGci; +}//Dblqh::writeCompletedGciLog() + +/* -------------------------------------------------------------------------- + * ------- WRITE A DIRTY PAGE DURING LOG EXECUTION ------- + * + * SUBROUTINE SHORT NAME: WD + * ------------------------------------------------------------------------- */ +void Dblqh::writeDirty(Signal* signal) +{ + logPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; + + // Calculate checksum for page + logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); + + seizeLfo(signal); + initLfo(signal); + lfoPtr.p->lfoPageNo = logPartPtr.p->prevFilepage; + lfoPtr.p->noPagesRw = 1; + lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_DIRTY; + lfoPtr.p->firstLfoPage = logPagePtr.i; + signal->theData[0] = logFilePtr.p->fileRef; + signal->theData[1] = cownref; + signal->theData[2] = lfoPtr.i; + signal->theData[3] = ZLIST_OF_PAIRS_SYNCH; + signal->theData[4] = ZVAR_NO_LOG_PAGE_WORD; + signal->theData[5] = 1; + signal->theData[6] = logPagePtr.i; + signal->theData[7] = logPartPtr.p->prevFilepage; + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); +}//Dblqh::writeDirty() + +/* -------------------------------------------------------------------------- + * ------- WRITE A WORD INTO THE LOG, CHECK FOR NEW PAGE ------- + * + * SUBROUTINE SHORT NAME: WLW + * ------------------------------------------------------------------------- */ +void Dblqh::writeLogWord(Signal* signal, Uint32 data) +{ + Uint32 logPos = logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]; + ndbrequire(logPos < ZPAGE_SIZE); + logPagePtr.p->logPageWord[logPos] = data; + logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + 1; + if ((logPos + 1) == ZPAGE_SIZE) { + jam(); + completedLogPage(signal, ZNORMAL); + seizeLogpage(signal); + initLogpage(signal); + logFilePtr.p->currentLogpage = logPagePtr.i; + logFilePtr.p->currentFilepage++; + }//if +}//Dblqh::writeLogWord() + +/* -------------------------------------------------------------------------- + * ------- WRITE A NEXT LOG RECORD AND CHANGE TO NEXT MBYTE ------- + * + * SUBROUTINE SHORT NAME: WNL +// Input Pointers: +// logFilePtr(Redefines) +// logPagePtr (Redefines) +// logPartPtr + * ------------------------------------------------------------------------- */ +void Dblqh::writeNextLog(Signal* signal) +{ + LogFileRecordPtr wnlNextLogFilePtr; + UintR twnlNextFileNo; + UintR twnlNewMbyte; + UintR twnlRemWords; + UintR twnlNextMbyte; + +/* -------------------------------------------------- */ +/* CALCULATE THE NEW NUMBER OF REMAINING WORDS */ +/* AS 128*2036 WHERE 128 * 8 KBYTE = 1 MBYTE */ +/* AND 2036 IS THE NUMBER OF WORDS IN A PAGE */ +/* THAT IS USED FOR LOG INFORMATION. */ +/* -------------------------------------------------- */ + twnlRemWords = ZPAGE_SIZE - ZPAGE_HEADER_SIZE; + twnlRemWords = twnlRemWords * ZPAGES_IN_MBYTE; + wnlNextLogFilePtr.i = logFilePtr.p->nextLogFile; + ptrCheckGuard(wnlNextLogFilePtr, clogFileFileSize, logFileRecord); +/* -------------------------------------------------- */ +/* WRITE THE NEXT LOG RECORD. */ +/* -------------------------------------------------- */ + ndbrequire(logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] < ZPAGE_SIZE); + logPagePtr.p->logPageWord[logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX]] = + ZNEXT_MBYTE_TYPE; + if (logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)) { + jam(); +/* -------------------------------------------------- */ +/* CALCULATE THE NEW REMAINING WORDS WHEN */ +/* CHANGING LOG FILE IS PERFORMED */ +/* -------------------------------------------------- */ + twnlRemWords = twnlRemWords - (ZPAGE_SIZE - ZPAGE_HEADER_SIZE); +/* -------------------------------------------------- */ +/* ENSURE THAT THE LOG PAGES ARE WRITTEN AFTER */ +/* WE HAVE CHANGED MBYTE. */ +/* -------------------------------------------------- */ +/* ENSURE LAST PAGE IN PREVIOUS MBYTE IS */ +/* WRITTEN AND THAT THE STATE OF THE WRITE IS */ +/* PROPERLY SET. */ +/* -------------------------------------------------- */ +/* WE HAVE TO CHANGE LOG FILE */ +/* -------------------------------------------------- */ + completedLogPage(signal, ZLAST_WRITE_IN_FILE); + if (wnlNextLogFilePtr.p->fileNo == 0) { + jam(); +/* -------------------------------------------------- */ +/* WE HAVE FINALISED A LOG LAP, START FROM LOG */ +/* FILE 0 AGAIN */ +/* -------------------------------------------------- */ + logPartPtr.p->logLap++; + }//if + logPartPtr.p->currentLogfile = wnlNextLogFilePtr.i; + logFilePtr.i = wnlNextLogFilePtr.i; + logFilePtr.p = wnlNextLogFilePtr.p; + twnlNewMbyte = 0; + } else { + jam(); +/* -------------------------------------------------- */ +/* INCREMENT THE CURRENT MBYTE */ +/* SET PAGE INDEX TO PAGE HEADER SIZE */ +/* -------------------------------------------------- */ + completedLogPage(signal, ZENFORCE_WRITE); + twnlNewMbyte = logFilePtr.p->currentMbyte + 1; + }//if +/* -------------------------------------------------- */ +/* CHANGE TO NEW LOG FILE IF NECESSARY */ +/* UPDATE THE FILE POSITION TO THE NEW MBYTE */ +/* FOUND IN PAGE PART OF TNEXT_LOG_PTR */ +/* ALLOCATE AND INITIATE A NEW PAGE SINCE WE */ +/* HAVE SENT THE PREVIOUS PAGE TO DISK. */ +/* SET THE NEW NUMBER OF REMAINING WORDS IN THE */ +/* NEW MBYTE ALLOCATED. */ +/* -------------------------------------------------- */ + logFilePtr.p->currentMbyte = twnlNewMbyte; + logFilePtr.p->filePosition = twnlNewMbyte * ZPAGES_IN_MBYTE; + logFilePtr.p->currentFilepage = twnlNewMbyte * ZPAGES_IN_MBYTE; + logFilePtr.p->remainingWordsInMbyte = twnlRemWords; + seizeLogpage(signal); + if (logFilePtr.p->currentMbyte == 0) { + jam(); + logFilePtr.p->lastPageWritten = 0; + if (logFilePtr.p->fileNo == 0) { + jam(); + releaseLogpage(signal); + logPagePtr.i = logFilePtr.p->logPageZero; + ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + }//if + }//if + initLogpage(signal); + logFilePtr.p->currentLogpage = logPagePtr.i; + if (logFilePtr.p->currentMbyte == 0) { + jam(); +/* -------------------------------------------------- */ +/* THIS IS A NEW FILE, WRITE THE FILE DESCRIPTOR*/ +/* ALSO OPEN THE NEXT LOG FILE TO ENSURE THAT */ +/* THIS FILE IS OPEN WHEN ITS TURN COMES. */ +/* -------------------------------------------------- */ + writeFileHeaderOpen(signal, ZNORMAL); + openNextLogfile(signal); + logFilePtr.p->fileChangeState = LogFileRecord::BOTH_WRITES_ONGOING; + }//if + if (logFilePtr.p->fileNo == logPartPtr.p->logTailFileNo) { + if (logFilePtr.p->currentMbyte == logPartPtr.p->logTailMbyte) { + jam(); +/* -------------------------------------------------- */ +/* THE HEAD AND TAIL HAS MET. THIS SHOULD NEVER */ +/* OCCUR. CAN HAPPEN IF THE LOCAL CHECKPOINTS */ +/* TAKE FAR TOO LONG TIME. SO TIMING PROBLEMS */ +/* CAN INVOKE THIS SYSTEM CRASH. HOWEVER ONLY */ +/* VERY SERIOUS TIMING PROBLEMS. */ +/* -------------------------------------------------- */ + systemError(signal); + }//if + }//if + if (logFilePtr.p->currentMbyte == (ZNO_MBYTES_IN_FILE - 1)) { + jam(); + twnlNextMbyte = 0; + if (logFilePtr.p->fileChangeState != LogFileRecord::NOT_ONGOING) { + jam(); + logPartPtr.p->logPartState = LogPartRecord::FILE_CHANGE_PROBLEM; + }//if + twnlNextFileNo = wnlNextLogFilePtr.p->fileNo; + } else { + jam(); + twnlNextMbyte = logFilePtr.p->currentMbyte + 1; + twnlNextFileNo = logFilePtr.p->fileNo; + }//if + if (twnlNextFileNo == logPartPtr.p->logTailFileNo) { + if (logPartPtr.p->logTailMbyte == twnlNextMbyte) { + jam(); +/* -------------------------------------------------- */ +/* THE NEXT MBYTE WILL BE THE TAIL. WE MUST */ +/* STOP LOGGING NEW OPERATIONS. THIS OPERATION */ +/* ALLOWED TO PASS. ALSO COMMIT, NEXT, COMPLETED*/ +/* GCI, ABORT AND FRAGMENT SPLIT IS ALLOWED. */ +/* OPERATIONS ARE ALLOWED AGAIN WHEN THE TAIL */ +/* IS MOVED FORWARD AS A RESULT OF A START_LCP */ +/* _ROUND SIGNAL ARRIVING FROM DBDIH. */ +/* -------------------------------------------------- */ + logPartPtr.p->logPartState = LogPartRecord::TAIL_PROBLEM; + }//if + }//if +}//Dblqh::writeNextLog() + +void +Dblqh::execDUMP_STATE_ORD(Signal* signal) +{ + DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0]; + if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersSize){ + infoEvent("LQH: m_commitAckMarkerPool: %d free size: %d", + m_commitAckMarkerPool.getNoOfFree(), + m_commitAckMarkerPool.getSize()); + } + if(dumpState->args[0] == DumpStateOrd::CommitAckMarkersDump){ + infoEvent("LQH: m_commitAckMarkerPool: %d free size: %d", + m_commitAckMarkerPool.getNoOfFree(), + m_commitAckMarkerPool.getSize()); + + CommitAckMarkerIterator iter; + for(m_commitAckMarkerHash.first(iter); iter.curr.i != RNIL; + m_commitAckMarkerHash.next(iter)){ + infoEvent("CommitAckMarker: i = %d (0x%x, 0x%x)" + " ApiRef: 0x%x apiOprec: 0x%x TcNodeId: %d", + iter.curr.i, + iter.curr.p->transid1, + iter.curr.p->transid2, + iter.curr.p->apiRef, + iter.curr.p->apiOprec, + iter.curr.p->tcNodeId); + } + } + + // Dump info about number of log pages + if(dumpState->args[0] == DumpStateOrd::LqhDumpNoLogPages){ + infoEvent("LQH: Log pages : %d Free: %d", + clogPageFileSize, + cnoOfLogPages); + } + + // Dump all defined tables that LQH knowns about + if(dumpState->args[0] == DumpStateOrd::LqhDumpAllDefinedTabs){ + for(Uint32 i = 0; i<ctabrecFileSize; i++){ + TablerecPtr tabPtr; + tabPtr.i = i; + ptrAss(tabPtr, tablerec); + if(tabPtr.p->tableStatus != Tablerec::NOT_DEFINED){ + infoEvent("Table %d Status: %d Usage: %d", + i, tabPtr.p->tableStatus, tabPtr.p->usageCount); + } + } + return; + } + + // Dump all ScanRecords + if (dumpState->args[0] == DumpStateOrd::LqhDumpAllScanRec){ + Uint32 recordNo = 0; + if (signal->length() == 1) + infoEvent("LQH: Dump all ScanRecords - size: %d", + cscanrecFileSize); + else if (signal->length() == 2) + recordNo = dumpState->args[1]; + else + return; + + dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec; + dumpState->args[1] = recordNo; + execDUMP_STATE_ORD(signal); + + if (recordNo < cscanrecFileSize-1){ + dumpState->args[0] = DumpStateOrd::LqhDumpAllScanRec; + dumpState->args[1] = recordNo+1; + sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); + } + return; + } + + // Dump all active ScanRecords + if (dumpState->args[0] == DumpStateOrd::LqhDumpAllActiveScanRec){ + Uint32 recordNo = 0; + if (signal->length() == 1) + infoEvent("LQH: Dump active ScanRecord - size: %d", + cscanrecFileSize); + else if (signal->length() == 2) + recordNo = dumpState->args[1]; + else + return; + + ScanRecordPtr sp; + sp.i = recordNo; + c_scanRecordPool.getPtr(scanptr); + if (sp.p->scanState != ScanRecord::SCAN_FREE){ + dumpState->args[0] = DumpStateOrd::LqhDumpOneScanRec; + dumpState->args[1] = recordNo; + execDUMP_STATE_ORD(signal); + } + + if (recordNo < cscanrecFileSize-1){ + dumpState->args[0] = DumpStateOrd::LqhDumpAllActiveScanRec; + dumpState->args[1] = recordNo+1; + sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB); + } + return; + } + + if(dumpState->args[0] == DumpStateOrd::LqhDumpOneScanRec){ + Uint32 recordNo = RNIL; + if (signal->length() == 2) + recordNo = dumpState->args[1]; + else + return; + + if (recordNo >= cscanrecFileSize) + return; + + ScanRecordPtr sp; + sp.i = recordNo; + c_scanRecordPool.getPtr(sp); + infoEvent("Dblqh::ScanRecord[%d]: state=%d, type=%d, " + "complStatus=%d, scanNodeId=%d", + sp.i, + sp.p->scanState, + sp.p->scanType, + sp.p->scanCompletedStatus, + sp.p->scanNodeId); + infoEvent(" apiBref=0x%x, scanAccPtr=%d", + sp.p->scanApiBlockref, + sp.p->scanAccPtr); + infoEvent(" copyptr=%d, ailen=%d, complOps=%d, concurrOps=%d", + sp.p->copyPtr, + sp.p->scanAiLength, + sp.p->m_curr_batch_size_rows, + sp.p->m_max_batch_size_rows); + infoEvent(" errCnt=%d, localFid=%d, schV=%d", + sp.p->scanErrorCounter, + sp.p->scanLocalFragid, + sp.p->scanSchemaVersion); + infoEvent(" stpid=%d, flag=%d, lhold=%d, lmode=%d, num=%d", + sp.p->scanStoredProcId, + sp.p->scanFlag, + sp.p->scanLockHold, + sp.p->scanLockMode, + sp.p->scanNumber); + infoEvent(" relCount=%d, TCwait=%d, TCRec=%d, KIflag=%d", + sp.p->scanReleaseCounter, + sp.p->scanTcWaiting, + sp.p->scanTcrec, + sp.p->scanKeyinfoFlag); + return; + } + if(dumpState->args[0] == DumpStateOrd::LqhDumpLcpState){ + + infoEvent("== LQH LCP STATE =="); + infoEvent(" clcpCompletedState=%d, c_lcpId=%d, cnoOfFragsCheckpointed=%d", + clcpCompletedState, + c_lcpId, + cnoOfFragsCheckpointed); + + LcpRecordPtr TlcpPtr; + // Print information about the current local checkpoint + TlcpPtr.i = 0; + ptrAss(TlcpPtr, lcpRecord); + infoEvent(" lcpState=%d firstLcpLocTup=%d firstLcpLocAcc=%d", + TlcpPtr.p->lcpState, + TlcpPtr.p->firstLcpLocTup, + TlcpPtr.p->firstLcpLocAcc); + infoEvent(" lcpAccptr=%d lastFragmentFlag=%d", + TlcpPtr.p->lcpAccptr, + TlcpPtr.p->lastFragmentFlag); + infoEvent("currentFragment.fragPtrI=%d", + TlcpPtr.p->currentFragment.fragPtrI); + infoEvent("currentFragment.lcpFragOrd.tableId=%d", + TlcpPtr.p->currentFragment.lcpFragOrd.tableId); + infoEvent(" lcpQueued=%d reportEmpty=%d", + TlcpPtr.p->lcpQueued, + TlcpPtr.p->reportEmpty); + char buf[8*_NDB_NODE_BITMASK_SIZE+1]; + infoEvent(" m_EMPTY_LCP_REQ=%d", + TlcpPtr.p->m_EMPTY_LCP_REQ.getText(buf)); + + return; + } + + + +}//Dblqh::execDUMP_STATE_ORD() + +void Dblqh::execSET_VAR_REQ(Signal* signal) +{ +#if 0 + SetVarReq* const setVarReq = (SetVarReq*)&signal->theData[0]; + ConfigParamId var = setVarReq->variable(); + + switch (var) { + + case NoOfConcurrentCheckpointsAfterRestart: + sendSignal(CMVMI_REF, GSN_SET_VAR_CONF, signal, 1, JBB); + break; + + case NoOfConcurrentCheckpointsDuringRestart: + // Valid only during start so value not set. + sendSignal(CMVMI_REF, GSN_SET_VAR_CONF, signal, 1, JBB); + break; + + default: + sendSignal(CMVMI_REF, GSN_SET_VAR_REF, signal, 1, JBB); + } // switch +#endif +}//execSET_VAR_REQ() + + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* ---------------------- TRIGGER HANDLING ------------------------ */ +/* ---------------------------------------------------------------- */ +/* */ +/* All trigger signals from TRIX are forwarded top TUP */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +// Trigger signals +void +Dblqh::execCREATE_TRIG_REQ(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference tupref = calcTupBlockRef(myNodeId); + + sendSignal(tupref, GSN_CREATE_TRIG_REQ, signal, CreateTrigReq::SignalLength, JBB); +} + +void +Dblqh::execCREATE_TRIG_CONF(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference dictref = calcDictBlockRef(myNodeId); + + sendSignal(dictref, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB); +} + +void +Dblqh::execCREATE_TRIG_REF(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference dictref = calcDictBlockRef(myNodeId); + + sendSignal(dictref, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB); +} + +void +Dblqh::execDROP_TRIG_REQ(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference tupref = calcTupBlockRef(myNodeId); + + sendSignal(tupref, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); +} + +void +Dblqh::execDROP_TRIG_CONF(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference dictref = calcDictBlockRef(myNodeId); + + sendSignal(dictref, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB); +} + +void +Dblqh::execDROP_TRIG_REF(Signal* signal) +{ + jamEntry(); + NodeId myNodeId = getOwnNodeId(); + BlockReference dictref = calcDictBlockRef(myNodeId); + + sendSignal(dictref, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB); +} + +Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){ + Uint32 checkSum = 37; +#ifdef VM_TRACE + for (Uint32 i = (ZPOS_CHECKSUM+1); i<ZPAGE_SIZE; i++) + checkSum = logP.p->logPageWord[i] ^ checkSum; +#endif + return checkSum; + } + |