summaryrefslogtreecommitdiff
path: root/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp')
-rw-r--r--storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp18661
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(&regAttrPtr->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], &regAttrinbufptr.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],
+ &regTcPtr->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],
+ &regDatabufptr.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],
+ &regTcPtr->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],
+ &regAttrinbufptr.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],
+ &regAttrinbufptr.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;
+ }
+