summaryrefslogtreecommitdiff
path: root/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp')
-rw-r--r--storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp11653
1 files changed, 11653 insertions, 0 deletions
diff --git a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
new file mode 100644
index 00000000000..a16c0da369b
--- /dev/null
+++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
@@ -0,0 +1,11653 @@
+/* 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 DBACC_C
+#include "Dbacc.hpp"
+#include <my_sys.h>
+
+#include <AttributeHeader.hpp>
+#include <signaldata/AccFrag.hpp>
+#include <signaldata/AccScan.hpp>
+#include <signaldata/AccLock.hpp>
+#include <signaldata/EventReport.hpp>
+#include <signaldata/FsConf.hpp>
+#include <signaldata/FsRef.hpp>
+#include <signaldata/FsRemoveReq.hpp>
+#include <signaldata/DropTab.hpp>
+#include <signaldata/DumpStateOrd.hpp>
+#include <SectionReader.hpp>
+
+// TO_DO_RONM is a label for comments on what needs to be improved in future versions
+// when more time is given.
+
+#ifdef VM_TRACE
+#define DEBUG(x) ndbout << "DBACC: "<< x << endl;
+#else
+#define DEBUG(x)
+#endif
+
+
+Uint32
+Dbacc::remainingUndoPages(){
+ Uint32 HeadPage = cundoposition >> ZUNDOPAGEINDEXBITS;
+ Uint32 TailPage = clastUndoPageIdWritten;
+
+ // Head must be larger or same as tail
+ ndbrequire(HeadPage>=TailPage);
+
+ Uint32 UsedPages = HeadPage - TailPage;
+ Int32 Remaining = cundopagesize - UsedPages;
+
+ // There can not be more than cundopagesize remaining
+ if (Remaining <= 0){
+ // No more undolog, crash node
+ progError(__LINE__,
+ ERR_NO_MORE_UNDOLOG,
+ "There are more than 1Mbyte undolog writes outstanding");
+ }
+ return Remaining;
+}
+
+void
+Dbacc::updateLastUndoPageIdWritten(Signal* signal, Uint32 aNewValue){
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_COMMIT) {
+ clastUndoPageIdWritten = aNewValue;
+ if (remainingUndoPages() >= ZMIN_UNDO_PAGES_AT_COMMIT) {
+ jam();
+ EXECUTE_DIRECT(DBLQH, GSN_ACC_COM_UNBLOCK, signal, 1);
+ jamEntry();
+ }//if
+ } else {
+ clastUndoPageIdWritten = aNewValue;
+ }//if
+}//Dbacc::updateLastUndoPageIdWritten()
+
+void
+Dbacc::updateUndoPositionPage(Signal* signal, Uint32 aNewValue){
+ if (remainingUndoPages() >= ZMIN_UNDO_PAGES_AT_COMMIT) {
+ cundoposition = aNewValue;
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_COMMIT) {
+ jam();
+ EXECUTE_DIRECT(DBLQH, GSN_ACC_COM_BLOCK, signal, 1);
+ jamEntry();
+ }//if
+ } else {
+ cundoposition = aNewValue;
+ }//if
+}//Dbacc::updateUndoPositionPage()
+
+// Signal entries and statement blocks
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* COMMON SIGNAL RECEPTION MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* CONTINUEB CONTINUE SIGNAL */
+/* ******************------------------------------+ */
+/* SENDER: ACC, LEVEL B */
+void Dbacc::execCONTINUEB(Signal* signal)
+{
+ Uint32 tcase;
+
+ jamEntry();
+ tcase = signal->theData[0];
+ tdata0 = signal->theData[1];
+ tresult = 0;
+ switch (tcase) {
+ case ZLOAD_BAL_LCP_TIMER:
+ if (clblPageOver == 0) {
+ jam();
+ clblPageCounter = clblPagesPerTick;
+ } else {
+ if (clblPageOver > clblPagesPerTick) {
+ jam();
+ clblPageOver = clblPageOver - clblPagesPerTick;
+ } else {
+ jam();
+ clblPageOver = 0;
+ clblPageCounter = clblPagesPerTick - clblPageOver;
+ }//if
+ }//if
+ signal->theData[0] = ZLOAD_BAL_LCP_TIMER;
+ sendSignalWithDelay(cownBlockref, GSN_CONTINUEB, signal, 100, 1);
+ return;
+ break;
+ case ZINITIALISE_RECORDS:
+ jam();
+ initialiseRecordsLab(signal, signal->theData[3], signal->theData[4]);
+ return;
+ break;
+ case ZSR_READ_PAGES_ALLOC:
+ jam();
+ fragrecptr.i = tdata0;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ srReadPagesAllocLab(signal);
+ return;
+ break;
+ case ZSTART_UNDO:
+ jam();
+ startUndoLab(signal);
+ return;
+ break;
+ case ZSEND_SCAN_HBREP:
+ jam();
+ sendScanHbRep(signal, tdata0);
+ break;
+ case ZREL_ROOT_FRAG:
+ {
+ jam();
+ Uint32 tableId = signal->theData[1];
+ releaseRootFragResources(signal, tableId);
+ break;
+ }
+ case ZREL_FRAG:
+ {
+ jam();
+ Uint32 fragIndex = signal->theData[1];
+ releaseFragResources(signal, fragIndex);
+ break;
+ }
+ case ZREL_DIR:
+ {
+ jam();
+ Uint32 fragIndex = signal->theData[1];
+ Uint32 dirIndex = signal->theData[2];
+ Uint32 startIndex = signal->theData[3];
+ releaseDirResources(signal, fragIndex, dirIndex, startIndex);
+ break;
+ }
+ case ZREPORT_MEMORY_USAGE:{
+ jam();
+ static int c_currentMemUsed = 0;
+ int now = (cnoOfAllocatedPages * 100)/cpagesize;
+ const int thresholds[] = { 99, 90, 80, 0};
+
+ Uint32 i = 0;
+ const Uint32 sz = sizeof(thresholds)/sizeof(thresholds[0]);
+ for(i = 0; i<sz; i++){
+ if(now >= thresholds[i]){
+ now = thresholds[i];
+ break;
+ }
+ }
+
+ if(now != c_currentMemUsed){
+ reportMemoryUsage(signal, now > c_currentMemUsed ? 1 : -1);
+ }
+
+ c_currentMemUsed = now;
+
+ signal->theData[0] = ZREPORT_MEMORY_USAGE;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 2000, 1);
+ return;
+ }
+
+ case ZLCP_OP_WRITE_RT_BREAK:
+ {
+ operationRecPtr.i= signal->theData[1];
+ fragrecptr.i= signal->theData[2];
+ lcpConnectptr.i= signal->theData[3];
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ lcp_write_op_to_undolog(signal);
+ return;
+ }
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ return;
+}//Dbacc::execCONTINUEB()
+
+/* ******************--------------------------------------------------------------- */
+/* FSCLOSECONF CLOSE FILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSCLOSECONF(Signal* signal)
+{
+ jamEntry();
+ fsConnectptr.i = signal->theData[0];
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ tresult = 0;
+ switch (fsConnectptr.p->fsState) {
+ case WAIT_CLOSE_UNDO:
+ jam();
+ releaseFsConnRec(signal);
+ break;
+ case LCP_CLOSE_DATA:
+ jam();
+ checkSyncUndoPagesLab(signal);
+ return;
+ break;
+ case SR_CLOSE_DATA:
+ jam();
+ sendaccSrconfLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ return;
+}//Dbacc::execFSCLOSECONF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSCLOSEREF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSCLOSEREF(Signal* signal)
+{
+ jamEntry();
+ ndbrequire(false);
+}//Dbacc::execFSCLOSEREF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSOPENCONF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSOPENCONF(Signal* signal)
+{
+ jamEntry();
+ fsConnectptr.i = signal->theData[0];
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ tuserptr = signal->theData[1];
+ tresult = 0; /* RESULT CHECK VALUE */
+ switch (fsConnectptr.p->fsState) {
+ case WAIT_OPEN_UNDO_LCP:
+ jam();
+ lcpOpenUndofileConfLab(signal);
+ return;
+ break;
+ case WAIT_OPEN_UNDO_LCP_NEXT:
+ jam();
+ fsConnectptr.p->fsPtr = tuserptr;
+ return;
+ break;
+ case OPEN_UNDO_FILE_SR:
+ jam();
+ fsConnectptr.p->fsPtr = tuserptr;
+ srStartUndoLab(signal);
+ return;
+ break;
+ case WAIT_OPEN_DATA_FILE_FOR_WRITE:
+ jam();
+ lcpFsOpenConfLab(signal);
+ return;
+ break;
+ case WAIT_OPEN_DATA_FILE_FOR_READ:
+ jam();
+ fsConnectptr.p->fsPtr = tuserptr;
+ srFsOpenConfLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ return;
+}//Dbacc::execFSOPENCONF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSOPENREF OPENFILE REF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSOPENREF(Signal* signal)
+{
+ jamEntry();
+ ndbrequire(false);
+}//Dbacc::execFSOPENREF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSREADCONF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSREADCONF(Signal* signal)
+{
+ jamEntry();
+ fsConnectptr.i = signal->theData[0];
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ tresult = 0; /* RESULT CHECK VALUE */
+ switch (fsConnectptr.p->fsState) {
+ case WAIT_READ_PAGE_ZERO:
+ jam();
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ srReadPageZeroLab(signal);
+ return;
+ break;
+ case WAIT_READ_DATA:
+ jam();
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ storeDataPageInDirectoryLab(signal);
+ return;
+ break;
+ case READ_UNDO_PAGE:
+ jam();
+ srDoUndoLab(signal);
+ return;
+ break;
+ case READ_UNDO_PAGE_AND_CLOSE:
+ jam();
+ fsConnectptr.p->fsState = WAIT_CLOSE_UNDO;
+ /* ************************ */
+ /* FSCLOSEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 0;
+ sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA);
+ /* FLAG = DO NOT DELETE FILE */
+ srDoUndoLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ return;
+}//Dbacc::execFSREADCONF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSREADRREF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSREADREF(Signal* signal)
+{
+ jamEntry();
+ progError(0, __LINE__, "Read of file refused");
+ return;
+}//Dbacc::execFSREADREF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSWRITECONF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSWRITECONF(Signal* signal)
+{
+ jamEntry();
+ fsOpptr.i = signal->theData[0];
+ ptrCheckGuard(fsOpptr, cfsOpsize, fsOprec);
+ /* FS_OPERATION PTR */
+ tresult = 0; /* RESULT CHECK VALUE */
+ fsConnectptr.i = fsOpptr.p->fsConptr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ fragrecptr.i = fsOpptr.p->fsOpfragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ switch (fsOpptr.p->fsOpstate) {
+ case WAIT_WRITE_UNDO:
+ jam();
+ updateLastUndoPageIdWritten(signal, fsOpptr.p->fsOpMemPage);
+ releaseFsOpRec(signal);
+ if (fragrecptr.p->nrWaitWriteUndoExit == 0) {
+ jam();
+ checkSendLcpConfLab(signal);
+ return;
+ } else {
+ jam();
+ fragrecptr.p->lastUndoIsStored = ZTRUE;
+ }//if
+ return;
+ break;
+ case WAIT_WRITE_UNDO_EXIT:
+ jam();
+ updateLastUndoPageIdWritten(signal, fsOpptr.p->fsOpMemPage);
+ releaseFsOpRec(signal);
+ if (fragrecptr.p->nrWaitWriteUndoExit > 0) {
+ jam();
+ fragrecptr.p->nrWaitWriteUndoExit--;
+ }//if
+ if (fsConnectptr.p->fsState == WAIT_CLOSE_UNDO) {
+ jam();
+ /* ************************ */
+ /* FSCLOSEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = ZFALSE;
+ sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA);
+ }//if
+ if (fragrecptr.p->nrWaitWriteUndoExit == 0) {
+ if (fragrecptr.p->lastUndoIsStored == ZTRUE) {
+ jam();
+ fragrecptr.p->lastUndoIsStored = ZFALSE;
+ checkSendLcpConfLab(signal);
+ return;
+ }//if
+ }//if
+ return;
+ break;
+ case WAIT_WRITE_DATA:
+ jam();
+ releaseFsOpRec(signal);
+ fragrecptr.p->activeDataFilePage += ZWRITEPAGESIZE;
+ fragrecptr.p->activeDataPage = 0;
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ switch (fragrecptr.p->fragState) {
+ case LCP_SEND_PAGES:
+ jam();
+ savepagesLab(signal);
+ return;
+ break;
+ case LCP_SEND_OVER_PAGES:
+ jam();
+ saveOverPagesLab(signal);
+ return;
+ break;
+ case LCP_SEND_ZERO_PAGE:
+ jam();
+ saveZeroPageLab(signal);
+ return;
+ break;
+ case WAIT_ZERO_PAGE_STORED:
+ jam();
+ lcpCloseDataFileLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ return;
+ break;
+ }//switch
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ return;
+}//Dbacc::execFSWRITECONF()
+
+/* ******************--------------------------------------------------------------- */
+/* FSWRITEREF OPENFILE CONF */
+/* ******************------------------------------+ */
+/* SENDER: FS, LEVEL B */
+void Dbacc::execFSWRITEREF(Signal* signal)
+{
+ jamEntry();
+ progError(0, __LINE__, "Write to file refused");
+ return;
+}//Dbacc::execFSWRITEREF()
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* */
+/* END OF COMMON SIGNAL RECEPTION MODULE */
+/* */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* */
+/* SYSTEM RESTART MODULE */
+/* */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+void Dbacc::execNDB_STTOR(Signal* signal)
+{
+ Uint32 tstartphase;
+ Uint32 tStartType;
+
+ jamEntry();
+ cndbcntrRef = signal->theData[0];
+ cmynodeid = signal->theData[1];
+ tstartphase = signal->theData[2];
+ tStartType = signal->theData[3];
+ switch (tstartphase) {
+ case ZSPH1:
+ jam();
+ ndbsttorryLab(signal);
+ return;
+ break;
+ case ZSPH2:
+ cnoLcpPages = 2 * (ZWRITEPAGESIZE + 1);
+ initialiseLcpPages(signal);
+ ndbsttorryLab(signal);
+ return;
+ break;
+ case ZSPH3:
+ if ((tStartType == NodeState::ST_NODE_RESTART) ||
+ (tStartType == NodeState::ST_INITIAL_NODE_RESTART)) {
+ jam();
+ //---------------------------------------------
+ // csystemRestart is used to check what is needed
+ // during log execution. When starting a node it
+ // is not a log execution and rather a normal
+ // execution. Thus we reset the variable here to
+ // avoid unnecessary system crashes.
+ //---------------------------------------------
+ csystemRestart = ZFALSE;
+ }//if
+
+ signal->theData[0] = ZLOAD_BAL_LCP_TIMER;
+ sendSignalWithDelay(cownBlockref, GSN_CONTINUEB, signal, 100, 1);
+ break;
+ case ZSPH6:
+ jam();
+ clblPagesPerTick = clblPagesPerTickAfterSr;
+ csystemRestart = ZFALSE;
+
+ signal->theData[0] = ZREPORT_MEMORY_USAGE;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 2000, 1);
+ break;
+ default:
+ jam();
+ /*empty*/;
+ break;
+ }//switch
+ ndbsttorryLab(signal);
+ return;
+}//Dbacc::execNDB_STTOR()
+
+/* ******************--------------------------------------------------------------- */
+/* STTOR START / RESTART */
+/* ******************------------------------------+ */
+/* SENDER: ANY, LEVEL B */
+void Dbacc::execSTTOR(Signal* signal)
+{
+ jamEntry();
+ Uint32 tstartphase = signal->theData[1];
+ switch (tstartphase) {
+ case 1:
+ jam();
+ c_tup = (Dbtup*)globalData.getBlock(DBTUP);
+ ndbrequire(c_tup != 0);
+ break;
+ }
+ tuserblockref = signal->theData[3];
+ csignalkey = signal->theData[6];
+ sttorrysignalLab(signal);
+ return;
+}//Dbacc::execSTTOR()
+
+/* --------------------------------------------------------------------------------- */
+/* ZSPH1 */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::ndbrestart1Lab(Signal* signal)
+{
+ cmynodeid = globalData.ownId;
+ cownBlockref = numberToRef(DBACC, cmynodeid);
+ czero = 0;
+ cminusOne = czero - 1;
+ ctest = 0;
+ cundoLogActive = ZFALSE;
+ csystemRestart = ZTRUE;
+ clblPageOver = 0;
+ clblPageCounter = 0;
+ cactiveUndoFilePage = 0;
+ cprevUndoaddress = cminusOne;
+ cundoposition = 0;
+ clastUndoPageIdWritten = 0;
+ cactiveUndoFileVersion = RNIL;
+ cactiveOpenUndoFsPtr = RNIL;
+ for (Uint32 tmp = 0; tmp < ZMAX_UNDO_VERSION; tmp++) {
+ csrVersList[tmp] = RNIL;
+ }//for
+ return;
+}//Dbacc::ndbrestart1Lab()
+
+void Dbacc::initialiseRecordsLab(Signal* signal, Uint32 ref, Uint32 data)
+{
+ switch (tdata0) {
+ case 0:
+ jam();
+ initialiseTableRec(signal);
+ break;
+ case 1:
+ jam();
+ initialiseFsConnectionRec(signal);
+ break;
+ case 2:
+ jam();
+ initialiseFsOpRec(signal);
+ break;
+ case 3:
+ jam();
+ initialiseLcpConnectionRec(signal);
+ break;
+ case 4:
+ jam();
+ initialiseDirRec(signal);
+ break;
+ case 5:
+ jam();
+ initialiseDirRangeRec(signal);
+ break;
+ case 6:
+ jam();
+ initialiseFragRec(signal);
+ break;
+ case 7:
+ jam();
+ initialiseOverflowRec(signal);
+ break;
+ case 8:
+ jam();
+ initialiseOperationRec(signal);
+ break;
+ case 9:
+ jam();
+ initialisePageRec(signal);
+ break;
+ case 10:
+ jam();
+ initialiseRootfragRec(signal);
+ break;
+ case 11:
+ jam();
+ initialiseScanRec(signal);
+ break;
+ case 12:
+ jam();
+ initialiseSrVerRec(signal);
+
+ {
+ ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
+ conf->senderRef = reference();
+ conf->senderData = data;
+ sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
+ ReadConfigConf::SignalLength, JBB);
+ }
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+
+ signal->theData[0] = ZINITIALISE_RECORDS;
+ signal->theData[1] = tdata0 + 1;
+ signal->theData[2] = 0;
+ signal->theData[3] = ref;
+ signal->theData[4] = data;
+ sendSignal(reference(), GSN_CONTINUEB, signal, 5, JBB);
+ return;
+}//Dbacc::initialiseRecordsLab()
+
+/* *********************************<< */
+/* NDB_STTORRY */
+/* *********************************<< */
+void Dbacc::ndbsttorryLab(Signal* signal)
+{
+ signal->theData[0] = cownBlockref;
+ sendSignal(cndbcntrRef, GSN_NDB_STTORRY, signal, 1, JBB);
+ return;
+}//Dbacc::ndbsttorryLab()
+
+/* *********************************<< */
+/* SIZEALT_REP SIZE ALTERATION */
+/* *********************************<< */
+void Dbacc::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);
+
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_DIR_RANGE, &cdirrangesize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_DIR_ARRAY, &cdirarraysize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_FRAGMENT, &cfragmentsize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_OP_RECS, &coprecsize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_OVERFLOW_RECS,
+ &coverflowrecsize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_PAGE8, &cpagesize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_ROOT_FRAG,
+ &crootfragmentsize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_TABLE, &ctablesize));
+ ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_ACC_SCAN, &cscanRecSize));
+ initRecords();
+ ndbrestart1Lab(signal);
+
+ clblPagesPerTick = 50;
+ //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTick);
+
+ clblPagesPerTickAfterSr = 50;
+ //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTickAfterSr);
+
+ tdata0 = 0;
+ initialiseRecordsLab(signal, ref, senderData);
+ return;
+}//Dbacc::execSIZEALT_REP()
+
+/* *********************************<< */
+/* STTORRY */
+/* *********************************<< */
+void Dbacc::sttorrysignalLab(Signal* signal)
+{
+ signal->theData[0] = csignalkey;
+ signal->theData[1] = 3;
+ /* BLOCK CATEGORY */
+ signal->theData[2] = 2;
+ /* SIGNAL VERSION NUMBER */
+ signal->theData[3] = ZSPH1;
+ signal->theData[4] = 255;
+ sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 5, JBB);
+ /* END OF START PHASES */
+ return;
+}//Dbacc::sttorrysignalLab()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_DIR_REC */
+/* INITIALATES THE DIRECTORY RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseDirRec(Signal* signal)
+{
+ DirectoryarrayPtr idrDirptr;
+ ndbrequire(cdirarraysize > 0);
+ for (idrDirptr.i = 0; idrDirptr.i < cdirarraysize; idrDirptr.i++) {
+ refresh_watch_dog();
+ ptrAss(idrDirptr, directoryarray);
+ for (Uint32 i = 0; i <= 255; i++) {
+ idrDirptr.p->pagep[i] = RNIL;
+ }//for
+ }//for
+ cdirmemory = 0;
+ cfirstfreedir = RNIL;
+}//Dbacc::initialiseDirRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_DIR_RANGE_REC */
+/* INITIALATES THE DIR_RANGE RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseDirRangeRec(Signal* signal)
+{
+ DirRangePtr idrDirRangePtr;
+
+ ndbrequire(cdirrangesize > 0);
+ for (idrDirRangePtr.i = 0; idrDirRangePtr.i < cdirrangesize; idrDirRangePtr.i++) {
+ refresh_watch_dog();
+ ptrAss(idrDirRangePtr, dirRange);
+ idrDirRangePtr.p->dirArray[0] = idrDirRangePtr.i + 1;
+ for (Uint32 i = 1; i < 256; i++) {
+ idrDirRangePtr.p->dirArray[i] = RNIL;
+ }//for
+ }//for
+ idrDirRangePtr.i = cdirrangesize - 1;
+ ptrAss(idrDirRangePtr, dirRange);
+ idrDirRangePtr.p->dirArray[0] = RNIL;
+ cfirstfreeDirrange = 0;
+}//Dbacc::initialiseDirRangeRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_FRAG_REC */
+/* INITIALATES THE FRAGMENT RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseFragRec(Signal* signal)
+{
+ FragmentrecPtr regFragPtr;
+ ndbrequire(cfragmentsize > 0);
+ for (regFragPtr.i = 0; regFragPtr.i < cfragmentsize; regFragPtr.i++) {
+ jam();
+ refresh_watch_dog();
+ ptrAss(regFragPtr, fragmentrec);
+ initFragGeneral(regFragPtr);
+ regFragPtr.p->nextfreefrag = regFragPtr.i + 1;
+ }//for
+ regFragPtr.i = cfragmentsize - 1;
+ ptrAss(regFragPtr, fragmentrec);
+ regFragPtr.p->nextfreefrag = RNIL;
+ cfirstfreefrag = 0;
+}//Dbacc::initialiseFragRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_FS_CONNECTION_REC */
+/* INITIALATES THE FS_CONNECTION RECORDS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseFsConnectionRec(Signal* signal)
+{
+ ndbrequire(cfsConnectsize > 0);
+ for (fsConnectptr.i = 0; fsConnectptr.i < cfsConnectsize; fsConnectptr.i++) {
+ ptrAss(fsConnectptr, fsConnectrec);
+ fsConnectptr.p->fsNext = fsConnectptr.i + 1;
+ fsConnectptr.p->fsPrev = RNIL;
+ fsConnectptr.p->fragrecPtr = RNIL;
+ fsConnectptr.p->fsState = WAIT_NOTHING;
+ }//for
+ fsConnectptr.i = cfsConnectsize - 1;
+ ptrAss(fsConnectptr, fsConnectrec);
+ fsConnectptr.p->fsNext = RNIL; /* INITIALITES THE LAST CONNECTRECORD */
+ cfsFirstfreeconnect = 0; /* INITIATES THE FIRST FREE CONNECT RECORD */
+}//Dbacc::initialiseFsConnectionRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_FS_OP_REC */
+/* INITIALATES THE FS_OP RECORDS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseFsOpRec(Signal* signal)
+{
+ ndbrequire(cfsOpsize > 0);
+ for (fsOpptr.i = 0; fsOpptr.i < cfsOpsize; fsOpptr.i++) {
+ ptrAss(fsOpptr, fsOprec);
+ fsOpptr.p->fsOpnext = fsOpptr.i + 1;
+ fsOpptr.p->fsOpfragrecPtr = RNIL;
+ fsOpptr.p->fsConptr = RNIL;
+ fsOpptr.p->fsOpstate = WAIT_NOTHING;
+ }//for
+ fsOpptr.i = cfsOpsize - 1;
+ ptrAss(fsOpptr, fsOprec);
+ fsOpptr.p->fsOpnext = RNIL;
+ cfsFirstfreeop = 0;
+}//Dbacc::initialiseFsOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_LCP_CONNECTION_REC */
+/* INITIALATES THE LCP_CONNECTION RECORDS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseLcpConnectionRec(Signal* signal)
+{
+ ndbrequire(clcpConnectsize > 0);
+ for (lcpConnectptr.i = 0; lcpConnectptr.i < clcpConnectsize; lcpConnectptr.i++) {
+ ptrAss(lcpConnectptr, lcpConnectrec);
+ lcpConnectptr.p->nextLcpConn = lcpConnectptr.i + 1;
+ lcpConnectptr.p->lcpUserptr = RNIL;
+ lcpConnectptr.p->rootrecptr = RNIL;
+ lcpConnectptr.p->lcpstate = LCP_FREE;
+ }//for
+ lcpConnectptr.i = clcpConnectsize - 1;
+ ptrAss(lcpConnectptr, lcpConnectrec);
+ lcpConnectptr.p->nextLcpConn = RNIL;
+ cfirstfreelcpConnect = 0;
+}//Dbacc::initialiseLcpConnectionRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_OPERATION_REC */
+/* INITIALATES THE OPERATION RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseOperationRec(Signal* signal)
+{
+ ndbrequire(coprecsize > 0);
+ for (operationRecPtr.i = 0; operationRecPtr.i < coprecsize; operationRecPtr.i++) {
+ refresh_watch_dog();
+ ptrAss(operationRecPtr, operationrec);
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ operationRecPtr.p->opState = FREE_OP;
+ operationRecPtr.p->nextOp = operationRecPtr.i + 1;
+ }//for
+ operationRecPtr.i = coprecsize - 1;
+ ptrAss(operationRecPtr, operationrec);
+ operationRecPtr.p->nextOp = RNIL;
+ cfreeopRec = 0;
+}//Dbacc::initialiseOperationRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_OVERFLOW_REC */
+/* INITIALATES THE OVERFLOW RECORDS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseOverflowRec(Signal* signal)
+{
+ OverflowRecordPtr iorOverflowRecPtr;
+
+ ndbrequire(coverflowrecsize > 0);
+ for (iorOverflowRecPtr.i = 0; iorOverflowRecPtr.i < coverflowrecsize; iorOverflowRecPtr.i++) {
+ refresh_watch_dog();
+ ptrAss(iorOverflowRecPtr, overflowRecord);
+ iorOverflowRecPtr.p->nextfreeoverrec = iorOverflowRecPtr.i + 1;
+ }//for
+ iorOverflowRecPtr.i = coverflowrecsize - 1;
+ ptrAss(iorOverflowRecPtr, overflowRecord);
+ iorOverflowRecPtr.p->nextfreeoverrec = RNIL;
+ cfirstfreeoverrec = 0;
+}//Dbacc::initialiseOverflowRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_PAGE_REC */
+/* INITIALATES THE PAGE RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialisePageRec(Signal* signal)
+{
+ ndbrequire(cpagesize > 0);
+ cfreepage = 0;
+ cfirstfreepage = RNIL;
+ cnoOfAllocatedPages = 0;
+}//Dbacc::initialisePageRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_LCP_PAGES */
+/* INITIALATES THE LCP PAGE RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseLcpPages(Signal* signal)
+{
+ Uint32 tilpIndex;
+
+ ndbrequire(cnoLcpPages >= (2 * (ZWRITEPAGESIZE + 1)));
+ /* --------------------------------------------------------------------------------- */
+ /* AN ABSOLUTE MINIMUM IS THAT WE HAVE 16 LCP PAGES TO HANDLE TWO CONCURRENT */
+ /* LCP'S ON LOCAL FRAGMENTS. */
+ /* --------------------------------------------------------------------------------- */
+ ndbrequire(cpagesize >= (cnoLcpPages + 8));
+ /* --------------------------------------------------------------------------------- */
+ /* THE NUMBER OF PAGES MUST BE AT LEAST 8 PLUS THE NUMBER OF PAGES REQUIRED BY */
+ /* THE LOCAL CHECKPOINT PROCESS. THIS NUMBER IS 8 TIMES THE PARALLELISM OF */
+ /* LOCAL CHECKPOINTS. */
+ /* --------------------------------------------------------------------------------- */
+ /* --------------------------------------------------------------------------------- */
+ /* WE SET UP A LINKED LIST OF PAGES FOR EXCLUSIVE USE BY LOCAL CHECKPOINTS. */
+ /* --------------------------------------------------------------------------------- */
+ cfirstfreeLcpPage = RNIL;
+ for (tilpIndex = 0; tilpIndex < cnoLcpPages; tilpIndex++) {
+ jam();
+ seizePage(signal);
+ rlpPageptr = spPageptr;
+ releaseLcpPage(signal);
+ }//for
+}//Dbacc::initialiseLcpPages()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_ROOTFRAG_REC */
+/* INITIALATES THE ROOTFRAG RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseRootfragRec(Signal* signal)
+{
+ ndbrequire(crootfragmentsize > 0);
+ for (rootfragrecptr.i = 0; rootfragrecptr.i < crootfragmentsize; rootfragrecptr.i++) {
+ refresh_watch_dog();
+ ptrAss(rootfragrecptr, rootfragmentrec);
+ rootfragrecptr.p->nextroot = rootfragrecptr.i + 1;
+ rootfragrecptr.p->fragmentptr[0] = RNIL;
+ rootfragrecptr.p->fragmentptr[1] = RNIL;
+ }//for
+ rootfragrecptr.i = crootfragmentsize - 1;
+ ptrAss(rootfragrecptr, rootfragmentrec);
+ rootfragrecptr.p->nextroot = RNIL;
+ cfirstfreerootfrag = 0;
+}//Dbacc::initialiseRootfragRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_SCAN_REC */
+/* INITIALATES THE QUE_SCAN RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseScanRec(Signal* signal)
+{
+ ndbrequire(cscanRecSize > 0);
+ for (scanPtr.i = 0; scanPtr.i < cscanRecSize; scanPtr.i++) {
+ ptrAss(scanPtr, scanRec);
+ scanPtr.p->scanNextfreerec = scanPtr.i + 1;
+ scanPtr.p->scanState = ScanRec::SCAN_DISCONNECT;
+ scanPtr.p->scanTimer = 0;
+ scanPtr.p->scanContinuebCounter = 0;
+ }//for
+ scanPtr.i = cscanRecSize - 1;
+ ptrAss(scanPtr, scanRec);
+ scanPtr.p->scanNextfreerec = RNIL;
+ cfirstFreeScanRec = 0;
+}//Dbacc::initialiseScanRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_SR_VER_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseSrVerRec(Signal* signal)
+{
+ ndbrequire(csrVersionRecSize > 0);
+ for (srVersionPtr.i = 0; srVersionPtr.i < csrVersionRecSize; srVersionPtr.i++) {
+ ptrAss(srVersionPtr, srVersionRec);
+ srVersionPtr.p->nextFreeSr = srVersionPtr.i + 1;
+ }//for
+ srVersionPtr.i = csrVersionRecSize - 1;
+ ptrAss(srVersionPtr, srVersionRec);
+ srVersionPtr.p->nextFreeSr = RNIL;
+ cfirstFreeSrVersionRec = 0;
+}//Dbacc::initialiseSrVerRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INITIALISE_TABLE_REC */
+/* INITIALATES THE TABLE RECORDS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initialiseTableRec(Signal* signal)
+{
+ ndbrequire(ctablesize > 0);
+ for (tabptr.i = 0; tabptr.i < ctablesize; tabptr.i++) {
+ refresh_watch_dog();
+ ptrAss(tabptr, tabrec);
+ for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) {
+ tabptr.p->fragholder[i] = RNIL;
+ tabptr.p->fragptrholder[i] = RNIL;
+ }//for
+ tabptr.p->noOfKeyAttr = 0;
+ tabptr.p->hasCharAttr = 0;
+ for (Uint32 k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) {
+ tabptr.p->keyAttr[k].attributeDescriptor = 0;
+ tabptr.p->keyAttr[k].charsetInfo = 0;
+ }
+ }//for
+}//Dbacc::initialiseTableRec()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF SYSTEM RESTART MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* ADD/DELETE FRAGMENT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+
+void Dbacc::initRootfragrec(Signal* signal)
+{
+ const AccFragReq * const req = (AccFragReq*)&signal->theData[0];
+ rootfragrecptr.p->mytabptr = req->tableId;
+ rootfragrecptr.p->roothashcheck = req->kValue + req->lhFragBits;
+ rootfragrecptr.p->noOfElements = 0;
+ rootfragrecptr.p->m_commit_count = 0;
+ for (Uint32 i = 0; i < MAX_PARALLEL_SCANS_PER_FRAG; i++) {
+ rootfragrecptr.p->scan[i] = RNIL;
+ }//for
+}//Dbacc::initRootfragrec()
+
+void Dbacc::execACCFRAGREQ(Signal* signal)
+{
+ const AccFragReq * const req = (AccFragReq*)&signal->theData[0];
+ jamEntry();
+ if (ERROR_INSERTED(3001)) {
+ jam();
+ addFragRefuse(signal, 1);
+ CLEAR_ERROR_INSERT_VALUE;
+ return;
+ }
+ tabptr.i = req->tableId;
+#ifndef VM_TRACE
+ // config mismatch - do not crash if release compiled
+ if (tabptr.i >= ctablesize) {
+ jam();
+ addFragRefuse(signal, 640);
+ return;
+ }
+#endif
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ ndbrequire((req->reqInfo & 0xF) == ZADDFRAG);
+ ndbrequire(!getrootfragmentrec(signal, rootfragrecptr, req->fragId));
+ if (cfirstfreerootfrag == RNIL) {
+ jam();
+ addFragRefuse(signal, ZFULL_ROOTFRAGRECORD_ERROR);
+ return;
+ }//if
+ seizeRootfragrec(signal);
+ if (!addfragtotab(signal, rootfragrecptr.i, req->fragId)) {
+ jam();
+ releaseRootFragRecord(signal, rootfragrecptr);
+ addFragRefuse(signal, ZFULL_ROOTFRAGRECORD_ERROR);
+ return;
+ }//if
+ initRootfragrec(signal);
+ for (Uint32 i = 0; i < 2; i++) {
+ jam();
+ if (cfirstfreefrag == RNIL) {
+ jam();
+ addFragRefuse(signal, ZFULL_FRAGRECORD_ERROR);
+ return;
+ }//if
+ seizeFragrec(signal);
+ initFragGeneral(fragrecptr);
+ initFragAdd(signal, i, rootfragrecptr.i, fragrecptr);
+ rootfragrecptr.p->fragmentptr[i] = fragrecptr.i;
+ rootfragrecptr.p->fragmentid[i] = fragrecptr.p->myfid;
+ if (cfirstfreeDirrange == RNIL) {
+ jam();
+ addFragRefuse(signal, ZDIR_RANGE_ERROR);
+ return;
+ } else {
+ jam();
+ seizeDirrange(signal);
+ }//if
+ fragrecptr.p->directory = newDirRangePtr.i;
+ seizeDirectory(signal);
+ if (tresult < ZLIMIT_OF_ERROR) {
+ jam();
+ newDirRangePtr.p->dirArray[0] = sdDirptr.i;
+ } else {
+ jam();
+ addFragRefuse(signal, tresult);
+ return;
+ }//if
+ seizePage(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ addFragRefuse(signal, tresult);
+ return;
+ }//if
+ sdDirptr.p->pagep[0] = spPageptr.i;
+ tipPageId = 0;
+ inpPageptr = spPageptr;
+ initPage(signal);
+ if (cfirstfreeDirrange == RNIL) {
+ jam();
+ addFragRefuse(signal, ZDIR_RANGE_ERROR);
+ return;
+ } else {
+ jam();
+ seizeDirrange(signal);
+ }//if
+ fragrecptr.p->overflowdir = newDirRangePtr.i;
+ seizeDirectory(signal);
+ if (tresult < ZLIMIT_OF_ERROR) {
+ jam();
+ newDirRangePtr.p->dirArray[0] = sdDirptr.i;
+ } else {
+ jam();
+ addFragRefuse(signal, tresult);
+ return;
+ }//if
+ }//for
+ Uint32 userPtr = req->userPtr;
+ BlockReference retRef = req->userRef;
+ rootfragrecptr.p->rootState = ACTIVEROOT;
+ AccFragConf * const conf = (AccFragConf*)&signal->theData[0];
+
+ conf->userPtr = userPtr;
+ conf->rootFragPtr = rootfragrecptr.i;
+ conf->fragId[0] = rootfragrecptr.p->fragmentid[0];
+ conf->fragId[1] = rootfragrecptr.p->fragmentid[1];
+ conf->fragPtr[0] = rootfragrecptr.p->fragmentptr[0];
+ conf->fragPtr[1] = rootfragrecptr.p->fragmentptr[1];
+ conf->rootHashCheck = rootfragrecptr.p->roothashcheck;
+ sendSignal(retRef, GSN_ACCFRAGCONF, signal, AccFragConf::SignalLength, JBB);
+}//Dbacc::execACCFRAGREQ()
+
+void Dbacc::addFragRefuse(Signal* signal, Uint32 errorCode)
+{
+ const AccFragReq * const req = (AccFragReq*)&signal->theData[0];
+ AccFragRef * const ref = (AccFragRef*)&signal->theData[0];
+ Uint32 userPtr = req->userPtr;
+ BlockReference retRef = req->userRef;
+
+ ref->userPtr = userPtr;
+ ref->errorCode = errorCode;
+ sendSignal(retRef, GSN_ACCFRAGREF, signal, AccFragRef::SignalLength, JBB);
+ return;
+}//Dbacc::addFragRefuseEarly()
+
+void
+Dbacc::execTC_SCHVERREQ(Signal* signal)
+{
+ jamEntry();
+ if (! assembleFragments(signal)) {
+ jam();
+ return;
+ }
+ tabptr.i = signal->theData[0];
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ Uint32 noOfKeyAttr = signal->theData[6];
+ ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
+ Uint32 hasCharAttr = 0;
+
+ SegmentedSectionPtr s0Ptr;
+ signal->getSection(s0Ptr, 0);
+ SectionReader r0(s0Ptr, getSectionSegmentPool());
+ Uint32 i = 0;
+ while (i < noOfKeyAttr) {
+ jam();
+ Uint32 attributeDescriptor = ~0;
+ Uint32 csNumber = ~0;
+ if (! r0.getWord(&attributeDescriptor) ||
+ ! r0.getWord(&csNumber)) {
+ jam();
+ break;
+ }
+ CHARSET_INFO* cs = 0;
+ if (csNumber != 0) {
+ cs = all_charsets[csNumber];
+ ndbrequire(cs != 0);
+ hasCharAttr = 1;
+ }
+ tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor;
+ tabptr.p->keyAttr[i].charsetInfo = cs;
+ i++;
+ }
+ ndbrequire(i == noOfKeyAttr);
+ releaseSections(signal);
+
+ tabptr.p->noOfKeyAttr = noOfKeyAttr;
+ tabptr.p->hasCharAttr = hasCharAttr;
+
+ // copy char attr flag to each fragment
+ for (Uint32 i1 = 0; i1 < MAX_FRAG_PER_NODE; i1++) {
+ jam();
+ if (tabptr.p->fragptrholder[i1] != RNIL) {
+ rootfragrecptr.i = tabptr.p->fragptrholder[i1];
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ for (Uint32 i2 = 0; i2 < 2; i2++) {
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[i2];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->hasCharAttr = hasCharAttr;
+ }
+ }
+ }
+
+ // no reply to DICT
+}
+
+void
+Dbacc::execDROP_TAB_REQ(Signal* signal){
+ jamEntry();
+ DropTabReq* req = (DropTabReq*)signal->getDataPtr();
+
+ TabrecPtr tabPtr;
+ tabPtr.i = req->tableId;
+ ptrCheckGuard(tabPtr, ctablesize, tabrec);
+
+ tabPtr.p->tabUserRef = req->senderRef;
+ tabPtr.p->tabUserPtr = req->senderData;
+
+ signal->theData[0] = ZREL_ROOT_FRAG;
+ signal->theData[1] = tabPtr.i;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+}
+
+void Dbacc::releaseRootFragResources(Signal* signal, Uint32 tableId)
+{
+ RootfragmentrecPtr rootPtr;
+ TabrecPtr tabPtr;
+ tabPtr.i = tableId;
+ ptrCheckGuard(tabPtr, ctablesize, tabrec);
+ for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) {
+ jam();
+ if (tabPtr.p->fragholder[i] != RNIL) {
+ jam();
+ Uint32 fragIndex;
+ rootPtr.i = tabPtr.p->fragptrholder[i];
+ ptrCheckGuard(rootPtr, crootfragmentsize, rootfragmentrec);
+ if (rootPtr.p->fragmentptr[0] != RNIL) {
+ jam();
+ fragIndex = rootPtr.p->fragmentptr[0];
+ rootPtr.p->fragmentptr[0] = RNIL;
+ } else if (rootPtr.p->fragmentptr[1] != RNIL) {
+ jam();
+ fragIndex = rootPtr.p->fragmentptr[1];
+ rootPtr.p->fragmentptr[1] = RNIL;
+ } else {
+ jam();
+ releaseRootFragRecord(signal, rootPtr);
+ tabPtr.p->fragholder[i] = RNIL;
+ tabPtr.p->fragptrholder[i] = RNIL;
+ continue;
+ }//if
+ releaseFragResources(signal, fragIndex);
+ return;
+ }//if
+ }//for
+
+ /**
+ * Finished...
+ */
+ sendFSREMOVEREQ(signal, tableId);
+}//Dbacc::releaseRootFragResources()
+
+void Dbacc::releaseRootFragRecord(Signal* signal, RootfragmentrecPtr rootPtr)
+{
+ rootPtr.p->nextroot = cfirstfreerootfrag;
+ cfirstfreerootfrag = rootPtr.i;
+}//Dbacc::releaseRootFragRecord()
+
+void Dbacc::releaseFragResources(Signal* signal, Uint32 fragIndex)
+{
+ FragmentrecPtr regFragPtr;
+ regFragPtr.i = fragIndex;
+ ptrCheckGuard(regFragPtr, cfragmentsize, fragmentrec);
+ verifyFragCorrect(regFragPtr);
+ if (regFragPtr.p->directory != RNIL) {
+ jam();
+ releaseDirResources(signal, regFragPtr.i, regFragPtr.p->directory, 0);
+ regFragPtr.p->directory = RNIL;
+ } else if (regFragPtr.p->overflowdir != RNIL) {
+ jam();
+ releaseDirResources(signal, regFragPtr.i, regFragPtr.p->overflowdir, 0);
+ regFragPtr.p->overflowdir = RNIL;
+ } else if (regFragPtr.p->firstOverflowRec != RNIL) {
+ jam();
+ releaseOverflowResources(signal, regFragPtr);
+ } else if (regFragPtr.p->firstFreeDirindexRec != RNIL) {
+ jam();
+ releaseDirIndexResources(signal, regFragPtr);
+ } else {
+ RootfragmentrecPtr rootPtr;
+ jam();
+ rootPtr.i = regFragPtr.p->myroot;
+ ptrCheckGuard(rootPtr, crootfragmentsize, rootfragmentrec);
+ releaseFragRecord(signal, regFragPtr);
+ signal->theData[0] = ZREL_ROOT_FRAG;
+ signal->theData[1] = rootPtr.p->mytabptr;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+ }//if
+}//Dbacc::releaseFragResources()
+
+void Dbacc::verifyFragCorrect(FragmentrecPtr regFragPtr)
+{
+ for (Uint32 i = 0; i < ZWRITEPAGESIZE; i++) {
+ jam();
+ ndbrequire(regFragPtr.p->datapages[i] == RNIL);
+ }//for
+ ndbrequire(regFragPtr.p->lockOwnersList == RNIL);
+ ndbrequire(regFragPtr.p->firstWaitInQueOp == RNIL);
+ ndbrequire(regFragPtr.p->lastWaitInQueOp == RNIL);
+ ndbrequire(regFragPtr.p->sentWaitInQueOp == RNIL);
+ //ndbrequire(regFragPtr.p->fsConnPtr == RNIL);
+ ndbrequire(regFragPtr.p->zeroPagePtr == RNIL);
+ ndbrequire(regFragPtr.p->nrWaitWriteUndoExit == 0);
+ ndbrequire(regFragPtr.p->sentWaitInQueOp == RNIL);
+}//Dbacc::verifyFragCorrect()
+
+void Dbacc::releaseDirResources(Signal* signal,
+ Uint32 fragIndex,
+ Uint32 dirIndex,
+ Uint32 startIndex)
+{
+ DirRangePtr regDirRangePtr;
+ regDirRangePtr.i = dirIndex;
+ ptrCheckGuard(regDirRangePtr, cdirrangesize, dirRange);
+ for (Uint32 i = startIndex; i < 256; i++) {
+ jam();
+ if (regDirRangePtr.p->dirArray[i] != RNIL) {
+ jam();
+ Uint32 directoryIndex = regDirRangePtr.p->dirArray[i];
+ regDirRangePtr.p->dirArray[i] = RNIL;
+ releaseDirectoryResources(signal, fragIndex, dirIndex, (i + 1), directoryIndex);
+ return;
+ }//if
+ }//for
+ rdDirRangePtr = regDirRangePtr;
+ releaseDirrange(signal);
+ signal->theData[0] = ZREL_FRAG;
+ signal->theData[1] = fragIndex;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+}//Dbacc::releaseDirResources()
+
+void Dbacc::releaseDirectoryResources(Signal* signal,
+ Uint32 fragIndex,
+ Uint32 dirIndex,
+ Uint32 startIndex,
+ Uint32 directoryIndex)
+{
+ DirectoryarrayPtr regDirPtr;
+ regDirPtr.i = directoryIndex;
+ ptrCheckGuard(regDirPtr, cdirarraysize, directoryarray);
+ for (Uint32 i = 0; i < 256; i++) {
+ jam();
+ if (regDirPtr.p->pagep[i] != RNIL) {
+ jam();
+ rpPageptr.i = regDirPtr.p->pagep[i];
+ ptrCheckGuard(rpPageptr, cpagesize, page8);
+ releasePage(signal);
+ regDirPtr.p->pagep[i] = RNIL;
+ }//if
+ }//for
+ rdDirptr = regDirPtr;
+ releaseDirectory(signal);
+ signal->theData[0] = ZREL_DIR;
+ signal->theData[1] = fragIndex;
+ signal->theData[2] = dirIndex;
+ signal->theData[3] = startIndex;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 4, JBB);
+}//Dbacc::releaseDirectoryResources()
+
+void Dbacc::releaseOverflowResources(Signal* signal, FragmentrecPtr regFragPtr)
+{
+ Uint32 loopCount = 0;
+ OverflowRecordPtr regOverflowRecPtr;
+ while ((regFragPtr.p->firstOverflowRec != RNIL) &&
+ (loopCount < 1)) {
+ jam();
+ regOverflowRecPtr.i = regFragPtr.p->firstOverflowRec;
+ ptrCheckGuard(regOverflowRecPtr, coverflowrecsize, overflowRecord);
+ regFragPtr.p->firstOverflowRec = regOverflowRecPtr.p->nextOverRec;
+ rorOverflowRecPtr = regOverflowRecPtr;
+ releaseOverflowRec(signal);
+ loopCount++;
+ }//while
+ signal->theData[0] = ZREL_FRAG;
+ signal->theData[1] = regFragPtr.i;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+}//Dbacc::releaseOverflowResources()
+
+void Dbacc::releaseDirIndexResources(Signal* signal, FragmentrecPtr regFragPtr)
+{
+ Uint32 loopCount = 0;
+ OverflowRecordPtr regOverflowRecPtr;
+ while ((regFragPtr.p->firstFreeDirindexRec != RNIL) &&
+ (loopCount < 1)) {
+ jam();
+ regOverflowRecPtr.i = regFragPtr.p->firstFreeDirindexRec;
+ ptrCheckGuard(regOverflowRecPtr, coverflowrecsize, overflowRecord);
+ regFragPtr.p->firstFreeDirindexRec = regOverflowRecPtr.p->nextOverList;
+ rorOverflowRecPtr = regOverflowRecPtr;
+ releaseOverflowRec(signal);
+ loopCount++;
+ }//while
+ signal->theData[0] = ZREL_FRAG;
+ signal->theData[1] = regFragPtr.i;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+}//Dbacc::releaseDirIndexResources()
+
+void Dbacc::releaseFragRecord(Signal* signal, FragmentrecPtr regFragPtr)
+{
+ regFragPtr.p->nextfreefrag = cfirstfreefrag;
+ cfirstfreefrag = regFragPtr.i;
+ initFragGeneral(regFragPtr);
+}//Dbacc::releaseFragRecord()
+
+void Dbacc::sendFSREMOVEREQ(Signal* signal, Uint32 tableId)
+{
+ FsRemoveReq * const fsReq = (FsRemoveReq *)signal->getDataPtrSend();
+ fsReq->userReference = cownBlockref;
+ fsReq->userPointer = tableId;
+ fsReq->fileNumber[0] = tableId;
+ fsReq->fileNumber[1] = (Uint32)-1; // Remove all fragments
+ fsReq->fileNumber[2] = (Uint32)-1; // Remove all data files within fragment
+ fsReq->fileNumber[3] = 255 | // No P-value used here
+ (3 << 8) | // Data-files in D3
+ (0 << 16) | // Data-files
+ (1 << 24); // Version 1 of fileNumber
+ fsReq->directory = 1;
+ fsReq->ownDirectory = 1;
+ sendSignal(NDBFS_REF, GSN_FSREMOVEREQ, signal, FsRemoveReq::SignalLength, JBA);
+}//Dbacc::sendFSREMOVEREQ()
+
+void Dbacc::execFSREMOVECONF(Signal* signal)
+{
+ FsConf * const fsConf = (FsConf *)signal->getDataPtrSend();
+ TabrecPtr tabPtr;
+ tabPtr.i = fsConf->userPointer;
+ ptrCheckGuard(tabPtr, ctablesize, tabrec);
+
+ DropTabConf * const dropConf = (DropTabConf *)signal->getDataPtrSend();
+ dropConf->senderRef = reference();
+ dropConf->senderData = tabPtr.p->tabUserPtr;
+ dropConf->tableId = tabPtr.i;
+ sendSignal(tabPtr.p->tabUserRef, GSN_DROP_TAB_CONF,
+ signal, DropTabConf::SignalLength, JBB);
+
+ tabPtr.p->tabUserPtr = RNIL;
+ tabPtr.p->tabUserRef = 0;
+}//Dbacc::execFSREMOVECONF()
+
+void Dbacc::execFSREMOVEREF(Signal* signal)
+{
+ ndbrequire(false);
+}//Dbacc::execFSREMOVEREF()
+
+/* -------------------------------------------------------------------------- */
+/* ADDFRAGTOTAB */
+/* DESCRIPTION: PUTS A FRAGMENT ID AND A POINTER TO ITS RECORD INTO */
+/* TABLE ARRRAY OF THE TABLE RECORD. */
+/* -------------------------------------------------------------------------- */
+bool Dbacc::addfragtotab(Signal* signal, Uint32 rootIndex, Uint32 fid)
+{
+ for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) {
+ jam();
+ if (tabptr.p->fragholder[i] == RNIL) {
+ jam();
+ tabptr.p->fragholder[i] = fid;
+ tabptr.p->fragptrholder[i] = rootIndex;
+ return true;
+ }//if
+ }//for
+ return false;
+}//Dbacc::addfragtotab()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF ADD/DELETE FRAGMENT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* CONNECTION MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACCSEIZEREQ SEIZE REQ */
+/* SENDER: LQH, LEVEL B */
+/* ENTER ACCSEIZEREQ WITH */
+/* TUSERPTR , CONECTION PTR OF LQH */
+/* TUSERBLOCKREF BLOCK REFERENCE OF LQH */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACCSEIZEREQ SEIZE REQ */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACCSEIZEREQ(Signal* signal)
+{
+ jamEntry();
+ tuserptr = signal->theData[0];
+ /* CONECTION PTR OF LQH */
+ tuserblockref = signal->theData[1];
+ /* BLOCK REFERENCE OF LQH */
+ tresult = 0;
+ if (cfreeopRec == RNIL) {
+ jam();
+ refaccConnectLab(signal);
+ return;
+ }//if
+ seizeOpRec(signal);
+ ptrGuard(operationRecPtr);
+ operationRecPtr.p->userptr = tuserptr;
+ operationRecPtr.p->userblockref = tuserblockref;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ operationRecPtr.p->transactionstate = IDLE;
+ /* ******************************< */
+ /* ACCSEIZECONF */
+ /* ******************************< */
+ signal->theData[0] = tuserptr;
+ signal->theData[1] = operationRecPtr.i;
+ sendSignal(tuserblockref, GSN_ACCSEIZECONF, signal, 2, JBB);
+ return;
+}//Dbacc::execACCSEIZEREQ()
+
+void Dbacc::refaccConnectLab(Signal* signal)
+{
+ tresult = ZCONNECT_SIZE_ERROR;
+ /* ******************************< */
+ /* ACCSEIZEREF */
+ /* ******************************< */
+ signal->theData[0] = tuserptr;
+ signal->theData[1] = tresult;
+ sendSignal(tuserblockref, GSN_ACCSEIZEREF, signal, 2, JBB);
+ return;
+}//Dbacc::refaccConnectLab()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF CONNECTION MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* EXECUTE OPERATION MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* INIT_OP_REC */
+/* INFORMATION WHICH IS RECIEVED BY ACCKEYREQ WILL BE SAVED */
+/* IN THE OPERATION RECORD. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initOpRec(Signal* signal)
+{
+ register Uint32 Treqinfo;
+
+ Treqinfo = signal->theData[2];
+
+ operationRecPtr.p->hashValue = signal->theData[3];
+ operationRecPtr.p->tupkeylen = signal->theData[4];
+ operationRecPtr.p->xfrmtupkeylen = signal->theData[4];
+ operationRecPtr.p->transId1 = signal->theData[5];
+ operationRecPtr.p->transId2 = signal->theData[6];
+ operationRecPtr.p->transactionstate = ACTIVE;
+ operationRecPtr.p->commitDeleteCheckFlag = ZFALSE;
+ operationRecPtr.p->operation = Treqinfo & 0x7;
+ /* --------------------------------------------------------------------------------- */
+ // opSimple is not used in this version. Is needed for deadlock handling later on.
+ /* --------------------------------------------------------------------------------- */
+ // operationRecPtr.p->opSimple = (Treqinfo >> 3) & 0x1;
+
+ operationRecPtr.p->lockMode = (Treqinfo >> 4) & 0x3;
+
+ Uint32 readFlag = (((Treqinfo >> 4) & 0x3) == 0); // Only 1 if Read
+ Uint32 dirtyFlag = (((Treqinfo >> 6) & 0x1) == 1); // Only 1 if Dirty
+ Uint32 dirtyReadFlag = readFlag & dirtyFlag;
+ operationRecPtr.p->dirtyRead = dirtyReadFlag;
+
+ operationRecPtr.p->nodeType = (Treqinfo >> 7) & 0x3;
+ operationRecPtr.p->fid = fragrecptr.p->myfid;
+ operationRecPtr.p->fragptr = fragrecptr.i;
+ operationRecPtr.p->nextParallelQue = RNIL;
+ operationRecPtr.p->prevParallelQue = RNIL;
+ operationRecPtr.p->prevQueOp = RNIL;
+ operationRecPtr.p->nextQueOp = RNIL;
+ operationRecPtr.p->nextSerialQue = RNIL;
+ operationRecPtr.p->prevSerialQue = RNIL;
+ operationRecPtr.p->elementPage = RNIL;
+ operationRecPtr.p->keyinfoPage = RNIL;
+ operationRecPtr.p->lockOwner = ZFALSE;
+ operationRecPtr.p->insertIsDone = ZFALSE;
+ operationRecPtr.p->elementIsDisappeared = ZFALSE;
+ operationRecPtr.p->insertDeleteLen = fragrecptr.p->elementLength;
+ operationRecPtr.p->longPagePtr = RNIL;
+ operationRecPtr.p->longKeyPageIndex = RNIL;
+ operationRecPtr.p->scanRecPtr = RNIL;
+
+ // bit to mark lock operation
+ operationRecPtr.p->isAccLockReq = (Treqinfo >> 31) & 0x1;
+
+ // undo log is not run via ACCKEYREQ
+ operationRecPtr.p->isUndoLogReq = 0;
+}//Dbacc::initOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEND_ACCKEYCONF */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::sendAcckeyconf(Signal* signal)
+{
+ signal->theData[0] = operationRecPtr.p->userptr;
+ signal->theData[1] = operationRecPtr.p->insertIsDone;
+ signal->theData[2] = operationRecPtr.p->fid;
+ signal->theData[3] = operationRecPtr.p->localdata[0];
+ signal->theData[4] = operationRecPtr.p->localdata[1];
+ signal->theData[5] = fragrecptr.p->localkeylen;
+}//Dbacc::sendAcckeyconf()
+
+
+void Dbacc::ACCKEY_error(Uint32 fromWhere)
+{
+ switch(fromWhere) {
+ case 0:
+ ndbrequire(false);
+ case 1:
+ ndbrequire(false);
+ case 2:
+ ndbrequire(false);
+ case 3:
+ ndbrequire(false);
+ case 4:
+ ndbrequire(false);
+ case 5:
+ ndbrequire(false);
+ case 6:
+ ndbrequire(false);
+ case 7:
+ ndbrequire(false);
+ case 8:
+ ndbrequire(false);
+ case 9:
+ ndbrequire(false);
+ default:
+ ndbrequire(false);
+ }//switch
+}//Dbacc::ACCKEY_error()
+
+/* ******************--------------------------------------------------------------- */
+/* ACCKEYREQ REQUEST FOR INSERT, DELETE, */
+/* RERAD AND UPDATE, A TUPLE. */
+/* SENDER: LQH, LEVEL B */
+/* SIGNAL DATA: OPERATION_REC_PTR, CONNECTION PTR */
+/* TABPTR, TABLE ID = TABLE RECORD POINTER */
+/* TREQINFO, */
+/* THASHVALUE, HASH VALUE OF THE TUP */
+/* TKEYLEN, LENGTH OF THE PRIMARY KEYS */
+/* TKEY1, PRIMARY KEY 1 */
+/* TKEY2, PRIMARY KEY 2 */
+/* TKEY3, PRIMARY KEY 3 */
+/* TKEY4, PRIMARY KEY 4 */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::execACCKEYREQ(Signal* signal)
+{
+ jamEntry();
+ operationRecPtr.i = signal->theData[0]; /* CONNECTION PTR */
+ fragrecptr.i = signal->theData[1]; /* FRAGMENT RECORD POINTER */
+ if (!((operationRecPtr.i < coprecsize) ||
+ (fragrecptr.i < cfragmentsize))) {
+ ACCKEY_error(0);
+ return;
+ }//if
+ ptrAss(operationRecPtr, operationrec);
+ ptrAss(fragrecptr, fragmentrec);
+ ndbrequire(operationRecPtr.p->transactionstate == IDLE);
+
+ initOpRec(signal);
+ // normalize key if any char attr
+ if (! operationRecPtr.p->isAccLockReq && fragrecptr.p->hasCharAttr)
+ xfrmKeyData(signal);
+
+ /*---------------------------------------------------------------*/
+ /* */
+ /* WE WILL USE THE HASH VALUE TO LOOK UP THE PROPER MEMORY */
+ /* PAGE AND MEMORY PAGE INDEX TO START THE SEARCH WITHIN. */
+ /* WE REMEMBER THESE ADDRESS IF WE LATER NEED TO INSERT */
+ /* THE ITEM AFTER NOT FINDING THE ITEM. */
+ /*---------------------------------------------------------------*/
+ getElement(signal);
+
+ if (tgeResult == ZTRUE) {
+ switch (operationRecPtr.p->operation) {
+ case ZREAD:
+ case ZUPDATE:
+ case ZDELETE:
+ case ZWRITE:
+ case ZSCAN_OP:
+ if (!tgeLocked){
+ sendAcckeyconf(signal);
+ if (operationRecPtr.p->dirtyRead == ZFALSE) {
+ /*---------------------------------------------------------------*/
+ // It is not a dirty read. We proceed by locking and continue with
+ // the operation.
+ /*---------------------------------------------------------------*/
+ Uint32 eh = gePageptr.p->word32[tgeElementptr];
+ operationRecPtr.p->scanBits = ElementHeader::getScanBits(eh);
+ operationRecPtr.p->hashvaluePart = ElementHeader::getHashValuePart(eh);
+ operationRecPtr.p->elementPage = gePageptr.i;
+ operationRecPtr.p->elementContainer = tgeContainerptr;
+ operationRecPtr.p->elementPointer = tgeElementptr;
+ operationRecPtr.p->elementIsforward = tgeForward;
+
+ eh = ElementHeader::setLocked(operationRecPtr.i);
+ dbgWord32(gePageptr, tgeElementptr, eh);
+ gePageptr.p->word32[tgeElementptr] = eh;
+
+ insertLockOwnersList(signal , operationRecPtr);
+ return;
+ } else {
+ jam();
+ /*---------------------------------------------------------------*/
+ // It is a dirty read. We do not lock anything. Set state to
+ // IDLE since no COMMIT call will come.
+ /*---------------------------------------------------------------*/
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ return;
+ }//if
+ } else {
+ jam();
+ accIsLockedLab(signal);
+ return;
+ }//if
+ break;
+ case ZINSERT:
+ jam();
+ insertExistElemLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ } else if (tgeResult == ZFALSE) {
+ switch (operationRecPtr.p->operation) {
+ case ZINSERT:
+ case ZWRITE:
+ jam();
+ // If a write operation makes an insert we switch operation to ZINSERT so
+ // that the commit-method knows an insert has been made and updates noOfElements.
+ operationRecPtr.p->operation = ZINSERT;
+ operationRecPtr.p->insertIsDone = ZTRUE;
+ insertelementLab(signal);
+ return;
+ break;
+ case ZREAD:
+ case ZUPDATE:
+ case ZDELETE:
+ case ZSCAN_OP:
+ jam();
+ acckeyref1Lab(signal, ZREAD_ERROR);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ } else {
+ jam();
+ acckeyref1Lab(signal, tgeResult);
+ return;
+ }//if
+ return;
+}//Dbacc::execACCKEYREQ()
+
+void
+Dbacc::xfrmKeyData(Signal* signal)
+{
+ tabptr.i = fragrecptr.p->myTableId;
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+
+ Uint32 dst[1024 * MAX_XFRM_MULTIPLY];
+ Uint32 dstSize = (sizeof(dst) >> 2);
+ Uint32* src = &signal->theData[7];
+ const Uint32 noOfKeyAttr = tabptr.p->noOfKeyAttr;
+ Uint32 dstPos = 0;
+ Uint32 srcPos = 0;
+ Uint32 i = 0;
+
+ while (i < noOfKeyAttr) {
+ const Tabrec::KeyAttr& keyAttr = tabptr.p->keyAttr[i];
+
+ Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
+ Uint32 srcWords = (srcBytes + 3) / 4;
+ Uint32 dstWords = ~0;
+ uchar* dstPtr = (uchar*)&dst[dstPos];
+ const uchar* srcPtr = (const uchar*)&src[srcPos];
+ CHARSET_INFO* cs = keyAttr.charsetInfo;
+
+ if (cs == 0) {
+ jam();
+ memcpy(dstPtr, srcPtr, srcWords << 2);
+ dstWords = srcWords;
+ } else {
+ jam();
+ Uint32 typeId = AttributeDescriptor::getType(keyAttr.attributeDescriptor);
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ ndbrequire(ok);
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ // see comment in DbtcMain.cpp
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0)
+ dstPtr[n++] = 0;
+ dstWords = (n >> 2);
+ }
+ dstPos += dstWords;
+ srcPos += srcWords;
+ i++;
+ }
+ memcpy(src, dst, dstPos << 2);
+ operationRecPtr.p->xfrmtupkeylen = dstPos;
+}
+
+void Dbacc::accIsLockedLab(Signal* signal)
+{
+ ndbrequire(csystemRestart == ZFALSE);
+ queOperPtr.i = ElementHeader::getOpPtrI(gePageptr.p->word32[tgeElementptr]);
+ ptrCheckGuard(queOperPtr, coprecsize, operationrec);
+ if (operationRecPtr.p->dirtyRead == ZFALSE) {
+ Uint32 return_result;
+ if (operationRecPtr.p->lockMode == ZREADLOCK) {
+ jam();
+ priPageptr = gePageptr;
+ tpriElementptr = tgeElementptr;
+ return_result = placeReadInLockQueue(signal);
+ } else {
+ jam();
+ pwiPageptr = gePageptr;
+ tpwiElementptr = tgeElementptr;
+ return_result = placeWriteInLockQueue(signal);
+ }//if
+ if (return_result == ZPARALLEL_QUEUE) {
+ jam();
+ sendAcckeyconf(signal);
+ return;
+ } else if (return_result == ZSERIAL_QUEUE) {
+ jam();
+ signal->theData[0] = RNIL;
+ return;
+ } else if (return_result == ZWRITE_ERROR) {
+ jam();
+ acckeyref1Lab(signal, return_result);
+ return;
+ }//if
+ ndbrequire(false);
+ } else {
+ if (queOperPtr.p->elementIsDisappeared == ZFALSE) {
+ jam();
+ /*---------------------------------------------------------------*/
+ // It is a dirty read. We do not lock anything. Set state to
+ // IDLE since no COMMIT call will arrive.
+ /*---------------------------------------------------------------*/
+ sendAcckeyconf(signal);
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ return;
+ } else {
+ jam();
+ /*---------------------------------------------------------------*/
+ // The tuple does not exist in the committed world currently.
+ // Report read error.
+ /*---------------------------------------------------------------*/
+ acckeyref1Lab(signal, ZREAD_ERROR);
+ return;
+ }//if
+ }//if
+}//Dbacc::accIsLockedLab()
+
+/* --------------------------------------------------------------------------------- */
+/* I N S E R T E X I S T E L E M E N T */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::insertExistElemLab(Signal* signal)
+{
+ if (!tgeLocked){
+ jam();
+ acckeyref1Lab(signal, ZWRITE_ERROR);/* THE ELEMENT ALREADY EXIST */
+ return;
+ }//if
+ accIsLockedLab(signal);
+}//Dbacc::insertExistElemLab()
+
+/* --------------------------------------------------------------------------------- */
+/* INSERTELEMENT */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::insertelementLab(Signal* signal)
+{
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_OPERATION) {
+ jam();
+ acckeyref1Lab(signal, ZTEMPORARY_ACC_UNDO_FAILURE);
+ return;
+ }//if
+ }//if
+ if (fragrecptr.p->firstOverflowRec == RNIL) {
+ jam();
+ allocOverflowPage(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ acckeyref1Lab(signal, tresult);
+ return;
+ }//if
+ }//if
+ if (fragrecptr.p->keyLength != operationRecPtr.p->tupkeylen) {
+ // historical
+ ndbrequire(fragrecptr.p->keyLength == 0);
+ }//if
+
+ signal->theData[0] = operationRecPtr.p->userptr;
+ Uint32 blockNo = refToBlock(operationRecPtr.p->userblockref);
+ EXECUTE_DIRECT(blockNo, GSN_LQH_ALLOCREQ, signal, 1);
+ jamEntry();
+ if (signal->theData[0] != 0) {
+ jam();
+ Uint32 result_code = signal->theData[0];
+ acckeyref1Lab(signal, result_code);
+ return;
+ }//if
+ Uint32 localKey = (signal->theData[1] << MAX_TUPLES_BITS) + signal->theData[2];
+
+ insertLockOwnersList(signal, operationRecPtr);
+
+ const Uint32 tmp = fragrecptr.p->k + fragrecptr.p->lhfragbits;
+ operationRecPtr.p->hashvaluePart =
+ (operationRecPtr.p->hashValue >> tmp) & 0xFFFF;
+ operationRecPtr.p->scanBits = 0; /* NOT ANY ACTIVE SCAN */
+ tidrElemhead = ElementHeader::setLocked(operationRecPtr.i);
+ idrPageptr = gdiPageptr;
+ tidrPageindex = tgdiPageindex;
+ tidrForward = ZTRUE;
+ idrOperationRecPtr = operationRecPtr;
+ clocalkey[0] = localKey;
+ operationRecPtr.p->localdata[0] = localKey;
+ /* --------------------------------------------------------------------------------- */
+ /* WE SET THE LOCAL KEY TO MINUS ONE TO INDICATE IT IS NOT YET VALID. */
+ /* --------------------------------------------------------------------------------- */
+ insertElement(signal);
+ sendAcckeyconf(signal);
+ return;
+}//Dbacc::insertelementLab()
+
+/* --------------------------------------------------------------------------------- */
+/* PLACE_READ_IN_LOCK_QUEUE */
+/* INPUT: OPERATION_REC_PTR OUR OPERATION POINTER */
+/* QUE_OPER_PTR LOCK QUEUE OWNER OPERATION POINTER */
+/* PRI_PAGEPTR PAGE POINTER OF ELEMENT */
+/* TPRI_ELEMENTPTR ELEMENT POINTER OF ELEMENT */
+/* OUTPUT TRESULT = */
+/* ZPARALLEL_QUEUE OPERATION PLACED IN PARALLEL QUEUE */
+/* OPERATION CAN PROCEED NOW. */
+/* ZSERIAL_QUEUE OPERATION PLACED IN SERIAL QUEUE */
+/* ERROR CODE OPERATION NEEDS ABORTING */
+/* THE ELEMENT WAS LOCKED AND WE WANT TO READ THE TUPLE. WE WILL CHECK THE LOCK */
+/* QUEUES TO PERFORM THE PROPER ACTION. */
+/* */
+/* IN SOME PLACES IN THE CODE BELOW THAT HANDLES WHAT TO DO WHEN THE TUPLE IS LOCKED */
+/* WE DO ASSUME THAT NEXT_PARALLEL_QUEUE AND NEXT_SERIAL_QUEUE ON OPERATION_REC_PTR */
+/* HAVE BEEN INITIALISED TO RNIL. THUS WE DO NOT PERFORM THIS ONCE MORE EVEN IF IT */
+/* COULD BE NICE FOR READABILITY. */
+/* --------------------------------------------------------------------------------- */
+Uint32 Dbacc::placeReadInLockQueue(Signal* signal)
+{
+ tgnptMainOpPtr = queOperPtr;
+ getNoParallelTransaction(signal);
+ if (tgnptNrTransaction == 1) {
+ if ((queOperPtr.p->transId1 == operationRecPtr.p->transId1) &&
+ (queOperPtr.p->transId2 == operationRecPtr.p->transId2)) {
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE PERFORMING A READ OPERATION AND THIS TRANSACTION ALREADY OWNS THE LOCK */
+ /* ALONE. PUT THE OPERATION LAST IN THE PARALLEL QUEUE. */
+ /* --------------------------------------------------------------------------------- */
+ jam();
+ mlpqOperPtr = queOperPtr;
+ moveLastParallelQueue(signal);
+ operationRecPtr.p->localdata[0] = queOperPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = queOperPtr.p->localdata[1];
+ operationRecPtr.p->prevParallelQue = mlpqOperPtr.i;
+ mlpqOperPtr.p->nextParallelQue = operationRecPtr.i;
+ switch (queOperPtr.p->lockMode) {
+ case ZREADLOCK:
+ jam();
+ /*empty*/;
+ break;
+ default:
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* IF THE TRANSACTION PREVIOUSLY SET A WRITE LOCK WE MUST ENSURE THAT ALL */
+ /* OPERATIONS IN THE PARALLEL QUEUE HAVE WRITE LOCK MODE TO AVOID STRANGE BUGS.*/
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr.p->lockMode = queOperPtr.p->lockMode;
+ break;
+ }//switch
+ return ZPARALLEL_QUEUE;
+ }//if
+ }//if
+ if (queOperPtr.p->nextSerialQue == RNIL) {
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE PERFORMING A READ OPERATION AND THERE IS NO SERIAL QUEUE. IF THERE IS NO */
+ /* WRITE OPERATION THAT OWNS THE LOCK OR ANY WRITE OPERATION IN THE PARALLEL QUEUE */
+ /* IT IS ENOUGH TO CHECK THE LOCK MODE OF THE LEADER IN THE PARALLEL QUEUE. IF IT IS */
+ /* A READ LOCK THEN WE PLACE OURSELVES IN THE PARALLEL QUEUE OTHERWISE WE GO ON TO */
+ /* PLACE OURSELVES IN THE SERIAL QUEUE. */
+ /* --------------------------------------------------------------------------------- */
+ switch (queOperPtr.p->lockMode) {
+ case ZREADLOCK:
+ jam();
+ mlpqOperPtr = queOperPtr;
+ moveLastParallelQueue(signal);
+ operationRecPtr.p->prevParallelQue = mlpqOperPtr.i;
+ mlpqOperPtr.p->nextParallelQue = operationRecPtr.i;
+ operationRecPtr.p->localdata[0] = queOperPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = queOperPtr.p->localdata[1];
+ return ZPARALLEL_QUEUE;
+ default:
+ jam();
+ queOperPtr.p->nextSerialQue = operationRecPtr.i;
+ operationRecPtr.p->prevSerialQue = queOperPtr.i;
+ putOpInFragWaitQue(signal);
+ break;
+ }//switch
+ } else {
+ jam();
+ placeSerialQueueRead(signal);
+ }//if
+ return ZSERIAL_QUEUE;
+}//Dbacc::placeReadInLockQueue()
+
+/* --------------------------------------------------------------------------------- */
+/* WE WILL CHECK IF THIS TRANSACTION IS ALREADY PLACED AT SOME SPOT IN THE PARALLEL */
+/* SERIAL QUEUE WITHOUT ANY NEIGHBORS FROM OTHER TRANSACTION. IF SO WE WILL INSERT */
+/* IT IN THAT PARALLEL QUEUE. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::placeSerialQueueRead(Signal* signal)
+{
+ readWriteOpPtr.i = queOperPtr.p->nextSerialQue;
+ ptrCheckGuard(readWriteOpPtr, coprecsize, operationrec);
+ PSQR_LOOP:
+ jam();
+ if (readWriteOpPtr.p->nextSerialQue == RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THERE WAS NO PREVIOUS OPERATION IN THIS TRANSACTION WHICH WE COULD PUT IT */
+ /* IN THE PARALLEL QUEUE TOGETHER WITH. */
+ /* --------------------------------------------------------------------------------- */
+ checkOnlyReadEntry(signal);
+ return;
+ }//if
+ tgnptMainOpPtr = readWriteOpPtr;
+ getNoParallelTransaction(signal);
+ if (tgnptNrTransaction == 1) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THERE WAS ONLY ONE TRANSACTION INVOLVED IN THE PARALLEL QUEUE. IF THIS IS OUR */
+ /* TRANSACTION WE CAN STILL GET HOLD OF THE LOCK. */
+ /* --------------------------------------------------------------------------------- */
+ if ((readWriteOpPtr.p->transId1 == operationRecPtr.p->transId1) &&
+ (readWriteOpPtr.p->transId2 == operationRecPtr.p->transId2)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE PERFORMING A READ IN THE SAME TRANSACTION WHERE WE ALREADY */
+ /* PREVIOUSLY HAVE EXECUTED AN OPERATION. INSERT-DELETE, READ-UPDATE, READ-READ, */
+ /* UPDATE-UPDATE, UPDATE-DELETE, READ-DELETE, INSERT-READ, INSERT-UPDATE ARE ALLOWED */
+ /* COMBINATIONS. A NEW INSERT AFTER A DELETE IS NOT ALLOWED AND SUCH AN INSERT WILL */
+ /* GO TO THE SERIAL LOCK QUEUE WHICH IT WILL NOT LEAVE UNTIL A TIME-OUT AND THE */
+ /* TRANSACTION IS ABORTED. READS AND UPDATES AFTER DELETES IS ALSO NOT ALLOWED. */
+ /* --------------------------------------------------------------------------------- */
+ mlpqOperPtr = readWriteOpPtr;
+ moveLastParallelQueue(signal);
+ readWriteOpPtr = mlpqOperPtr;
+ operationRecPtr.p->prevParallelQue = readWriteOpPtr.i;
+ readWriteOpPtr.p->nextParallelQue = operationRecPtr.i;
+ operationRecPtr.p->localdata[0] = readWriteOpPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = readWriteOpPtr.p->localdata[1];
+ switch (readWriteOpPtr.p->lockMode) {
+ case ZREADLOCK:
+ jam();
+ /*empty*/;
+ break;
+ default:
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* IF THE TRANSACTION PREVIOUSLY SET A WRITE LOCK WE MUST ENSURE THAT ALL */
+ /* OPERATIONS IN THE PARALLEL QUEUE HAVE WRITE LOCK MODE TO AVOID STRANGE BUGS.*/
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr.p->lockMode = readWriteOpPtr.p->lockMode;
+ break;
+ }//switch
+ putOpInFragWaitQue(signal);
+ return;
+ }//if
+ }//if
+ readWriteOpPtr.i = readWriteOpPtr.p->nextSerialQue;
+ ptrCheckGuard(readWriteOpPtr, coprecsize, operationrec);
+ goto PSQR_LOOP;
+}//Dbacc::placeSerialQueueRead()
+
+/* --------------------------------------------------------------------------------- */
+/* WE WILL CHECK IF THE LAST ENTRY IN THE SERIAL QUEUE CONTAINS ONLY READ */
+/* OPERATIONS. IF SO WE WILL INSERT IT IN THAT PARALLEL QUEUE. OTHERWISE WE */
+/* WILL PLACE IT AT THE END OF THE SERIAL QUEUE. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::checkOnlyReadEntry(Signal* signal)
+{
+ switch (readWriteOpPtr.p->lockMode) {
+ case ZREADLOCK:
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* SINCE THIS LAST QUEUE ONLY CONTAINS READ LOCKS WE CAN JOIN THE PARALLEL QUEUE AT */
+ /* THE END. */
+ /* --------------------------------------------------------------------------------- */
+ mlpqOperPtr = readWriteOpPtr;
+ moveLastParallelQueue(signal);
+ readWriteOpPtr = mlpqOperPtr;
+ operationRecPtr.p->prevParallelQue = readWriteOpPtr.i;
+ readWriteOpPtr.p->nextParallelQue = operationRecPtr.i;
+ operationRecPtr.p->localdata[0] = readWriteOpPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = readWriteOpPtr.p->localdata[1];
+ break;
+ default:
+ jam(); /* PUT THE OPERATION RECORD IN THE SERIAL QUEUE */
+ readWriteOpPtr.p->nextSerialQue = operationRecPtr.i;
+ operationRecPtr.p->prevSerialQue = readWriteOpPtr.i;
+ break;
+ }//switch
+ putOpInFragWaitQue(signal);
+}//Dbacc::checkOnlyReadEntry()
+
+/* --------------------------------------------------------------------------------- */
+/* GET_NO_PARALLEL_TRANSACTION */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::getNoParallelTransaction(Signal* signal)
+{
+ OperationrecPtr tnptOpPtr;
+
+ tgnptNrTransaction = 1;
+ tnptOpPtr.i = tgnptMainOpPtr.p->nextParallelQue;
+ while ((tnptOpPtr.i != RNIL) &&
+ (tgnptNrTransaction == 1)) {
+ jam();
+ ptrCheckGuard(tnptOpPtr, coprecsize, operationrec);
+ if ((tnptOpPtr.p->transId1 == tgnptMainOpPtr.p->transId1) &&
+ (tnptOpPtr.p->transId2 == tgnptMainOpPtr.p->transId2)) {
+ tnptOpPtr.i = tnptOpPtr.p->nextParallelQue;
+ } else {
+ jam();
+ tgnptNrTransaction++;
+ }//if
+ }//while
+}//Dbacc::getNoParallelTransaction()
+
+void Dbacc::moveLastParallelQueue(Signal* signal)
+{
+ while (mlpqOperPtr.p->nextParallelQue != RNIL) {
+ jam();
+ mlpqOperPtr.i = mlpqOperPtr.p->nextParallelQue;
+ ptrCheckGuard(mlpqOperPtr, coprecsize, operationrec);
+ }//if
+}//Dbacc::moveLastParallelQueue()
+
+void Dbacc::moveLastParallelQueueWrite(Signal* signal)
+{
+ /* --------------------------------------------------------------------------------- */
+ /* ENSURE THAT ALL OPERATIONS HAVE LOCK MODE SET TO WRITE SINCE WE INSERT A */
+ /* WRITE LOCK INTO THE PARALLEL QUEUE. */
+ /* --------------------------------------------------------------------------------- */
+ while (mlpqOperPtr.p->nextParallelQue != RNIL) {
+ jam();
+ mlpqOperPtr.p->lockMode = operationRecPtr.p->lockMode;
+ mlpqOperPtr.i = mlpqOperPtr.p->nextParallelQue;
+ ptrCheckGuard(mlpqOperPtr, coprecsize, operationrec);
+ }//if
+ mlpqOperPtr.p->lockMode = operationRecPtr.p->lockMode;
+}//Dbacc::moveLastParallelQueueWrite()
+
+/* --------------------------------------------------------------------------------- */
+/* PLACE_WRITE_IN_LOCK_QUEUE */
+/* INPUT: OPERATION_REC_PTR OUR OPERATION POINTER */
+/* QUE_OPER_PTR LOCK QUEUE OWNER OPERATION POINTER */
+/* PWI_PAGEPTR PAGE POINTER OF ELEMENT */
+/* TPWI_ELEMENTPTR ELEMENT POINTER OF ELEMENT */
+/* OUTPUT TRESULT = */
+/* ZPARALLEL_QUEUE OPERATION PLACED IN PARALLEL QUEUE */
+/* OPERATION CAN PROCEED NOW. */
+/* ZSERIAL_QUEUE OPERATION PLACED IN SERIAL QUEUE */
+/* ERROR CODE OPERATION NEEDS ABORTING */
+/* --------------------------------------------------------------------------------- */
+Uint32 Dbacc::placeWriteInLockQueue(Signal* signal)
+{
+ tgnptMainOpPtr = queOperPtr;
+ getNoParallelTransaction(signal);
+ if (!((tgnptNrTransaction == 1) &&
+ (queOperPtr.p->transId1 == operationRecPtr.p->transId1) &&
+ (queOperPtr.p->transId2 == operationRecPtr.p->transId2))) {
+ jam();
+ placeSerialQueueWrite(signal);
+ return ZSERIAL_QUEUE;
+ }//if
+
+ /*
+ WE ARE PERFORMING AN READ EXCLUSIVE, INSERT, UPDATE OR DELETE IN THE SAME
+ TRANSACTION WHERE WE PREVIOUSLY HAVE EXECUTED AN OPERATION.
+ Read-All, Update-All, Insert-All and Delete-Insert are allowed
+ combinations.
+ Delete-Read, Delete-Update and Delete-Delete are not an allowed
+ combination and will result in tuple not found error.
+ */
+ mlpqOperPtr = queOperPtr;
+ moveLastParallelQueueWrite(signal);
+
+ if (operationRecPtr.p->operation == ZINSERT &&
+ mlpqOperPtr.p->operation != ZDELETE){
+ jam();
+ return ZWRITE_ERROR;
+ }//if
+
+ operationRecPtr.p->localdata[0] = queOperPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = queOperPtr.p->localdata[1];
+ operationRecPtr.p->prevParallelQue = mlpqOperPtr.i;
+ mlpqOperPtr.p->nextParallelQue = operationRecPtr.i;
+ return ZPARALLEL_QUEUE;
+}//Dbacc::placeWriteInLockQueue()
+
+/* --------------------------------------------------------------------------------- */
+/* WE HAVE TO PLACE IT SOMEWHERE IN THE SERIAL QUEUE INSTEAD. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::placeSerialQueueWrite(Signal* signal)
+{
+ readWriteOpPtr = queOperPtr;
+ PSQW_LOOP:
+ if (readWriteOpPtr.p->nextSerialQue == RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE COULD NOT PUT IN ANY PARALLEL QUEUE. WE MUST PUT IT LAST IN THE SERIAL QUEUE. */
+ /* --------------------------------------------------------------------------------- */
+ readWriteOpPtr.p->nextSerialQue = operationRecPtr.i;
+ operationRecPtr.p->prevSerialQue = readWriteOpPtr.i;
+ putOpInFragWaitQue(signal);
+ return;
+ }//if
+ readWriteOpPtr.i = readWriteOpPtr.p->nextSerialQue;
+ ptrCheckGuard(readWriteOpPtr, coprecsize, operationrec);
+ tgnptMainOpPtr = readWriteOpPtr;
+ getNoParallelTransaction(signal);
+ if (tgnptNrTransaction == 1) {
+ /* --------------------------------------------------------------------------------- */
+ /* THERE WAS ONLY ONE TRANSACTION INVOLVED IN THE PARALLEL QUEUE. IF THIS IS OUR */
+ /* TRANSACTION WE CAN STILL GET HOLD OF THE LOCK. */
+ /* --------------------------------------------------------------------------------- */
+ if ((readWriteOpPtr.p->transId1 == operationRecPtr.p->transId1) &&
+ (readWriteOpPtr.p->transId2 == operationRecPtr.p->transId2)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE PERFORMING AN UPDATE OR DELETE IN THE SAME TRANSACTION WHERE WE ALREADY */
+ /* PREVIOUSLY HAVE EXECUTED AN OPERATION. INSERT-DELETE, READ-UPDATE, READ-READ, */
+ /* UPDATE-UPDATE, UPDATE-DELETE, READ-DELETE, INSERT-READ, INSERT-UPDATE ARE ALLOWED */
+ /* COMBINATIONS. A NEW INSERT AFTER A DELETE IS NOT ALLOWED AND SUCH AN INSERT WILL */
+ /* GO TO THE SERIAL LOCK QUEUE WHICH IT WILL NOT LEAVE UNTIL A TIME-OUT AND THE */
+ /* TRANSACTION IS ABORTED. READS AND UPDATES AFTER DELETES IS ALSO NOT ALLOWED. */
+ /* --------------------------------------------------------------------------------- */
+ mlpqOperPtr = readWriteOpPtr;
+ moveLastParallelQueueWrite(signal);
+ readWriteOpPtr = mlpqOperPtr;
+ operationRecPtr.p->prevParallelQue = readWriteOpPtr.i;
+ readWriteOpPtr.p->nextParallelQue = operationRecPtr.i;
+ operationRecPtr.p->localdata[0] = readWriteOpPtr.p->localdata[0];
+ operationRecPtr.p->localdata[1] = readWriteOpPtr.p->localdata[1];
+ putOpInFragWaitQue(signal);
+ return;
+ }//if
+ }//if
+ goto PSQW_LOOP;
+}//Dbacc::placeSerialQueueWrite()
+
+/* ------------------------------------------------------------------------- */
+/* ACC KEYREQ END */
+/* ------------------------------------------------------------------------- */
+void Dbacc::acckeyref1Lab(Signal* signal, Uint32 result_code)
+{
+ if (operationRecPtr.p->keyinfoPage != RNIL) {
+ jam();
+ rpPageptr.i = operationRecPtr.p->keyinfoPage;
+ ptrCheckGuard(rpPageptr, cpagesize, page8);
+ releasePage(signal);
+ operationRecPtr.p->keyinfoPage = RNIL;
+ }//if
+ operationRecPtr.p->transactionstate = WAIT_COMMIT_ABORT;
+ /* ************************<< */
+ /* ACCKEYREF */
+ /* ************************<< */
+ signal->theData[0] = cminusOne;
+ signal->theData[1] = result_code;
+ return;
+}//Dbacc::acckeyref1Lab()
+
+/* ******************--------------------------------------------------------------- */
+/* ACCMINUPDATE UPDATE LOCAL KEY REQ */
+/* DESCRIPTION: UPDATES LOCAL KEY OF AN ELEMENTS IN THE HASH TABLE */
+/* THIS SIGNAL IS WAITED AFTER ANY INSERT REQ */
+/* ENTER ACCMINUPDATE WITH SENDER: LQH, LEVEL B */
+/* OPERATION_REC_PTR, OPERATION RECORD PTR */
+/* CLOCALKEY(0), LOCAL KEY 1 */
+/* CLOCALKEY(1) LOCAL KEY 2 */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::execACCMINUPDATE(Signal* signal)
+{
+ Page8Ptr ulkPageidptr;
+ Uint32 tulkLocalPtr;
+ Uint32 tlocalkey1, tlocalkey2;
+ Uint32 TlogStart;
+
+ jamEntry();
+ operationRecPtr.i = signal->theData[0];
+ tlocalkey1 = signal->theData[1];
+ tlocalkey2 = signal->theData[2];
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ if (operationRecPtr.p->transactionstate == ACTIVE) {
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ulkPageidptr.i = operationRecPtr.p->elementPage;
+ tulkLocalPtr = operationRecPtr.p->elementPointer + operationRecPtr.p->elementIsforward;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ ptrCheckGuard(ulkPageidptr, cpagesize, page8);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ //----------------------------------------------------------
+ // To avoid undo log the element header we take care to only
+ // undo log the local key part.
+ //----------------------------------------------------------
+ if (operationRecPtr.p->elementIsforward == 1) {
+ jam();
+ TlogStart = tulkLocalPtr;
+ } else {
+ jam();
+ TlogStart = tulkLocalPtr - fragrecptr.p->localkeylen + 1;
+ }//if
+ datapageptr.p = ulkPageidptr.p;
+ cundoinfolength = fragrecptr.p->localkeylen;
+ cundoElemIndex = TlogStart;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(ulkPageidptr, tulkLocalPtr, tlocalkey1);
+ arrGuard(tulkLocalPtr, 2048);
+ ulkPageidptr.p->word32[tulkLocalPtr] = tlocalkey1;
+ operationRecPtr.p->localdata[0] = tlocalkey1;
+ if (fragrecptr.p->localkeylen == 1) {
+ return;
+ } else if (fragrecptr.p->localkeylen == 2) {
+ jam();
+ tulkLocalPtr = tulkLocalPtr + operationRecPtr.p->elementIsforward;
+ operationRecPtr.p->localdata[1] = tlocalkey2;
+ dbgWord32(ulkPageidptr, tulkLocalPtr, tlocalkey2);
+ arrGuard(tulkLocalPtr, 2048);
+ ulkPageidptr.p->word32[tulkLocalPtr] = tlocalkey2;
+ return;
+ } else {
+ jam();
+ }//if
+ }//if
+ ndbrequire(false);
+}//Dbacc::execACCMINUPDATE()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_COMMITREQ COMMIT TRANSACTION */
+/* SENDER: LQH, LEVEL B */
+/* INPUT: OPERATION_REC_PTR , */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::execACC_COMMITREQ(Signal* signal)
+{
+ Uint8 Toperation;
+ jamEntry();
+ operationRecPtr.i = signal->theData[0];
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ ndbrequire(operationRecPtr.p->transactionstate == ACTIVE);
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ commitOperation(signal);
+ Toperation = operationRecPtr.p->operation;
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ if(Toperation != ZREAD){
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ rootfragrecptr.p->m_commit_count++;
+ if (Toperation != ZINSERT) {
+ if (Toperation != ZDELETE) {
+ return;
+ } else {
+ jam();
+ rootfragrecptr.p->noOfElements--;
+ fragrecptr.p->slack += operationRecPtr.p->insertDeleteLen;
+ if (fragrecptr.p->slack > fragrecptr.p->slackCheck) {
+ /* TIME FOR JOIN BUCKETS PROCESS */
+ if (fragrecptr.p->expandCounter > 0) {
+ if (fragrecptr.p->expandFlag < 2) {
+ jam();
+ signal->theData[0] = fragrecptr.i;
+ signal->theData[1] = fragrecptr.p->p;
+ signal->theData[2] = fragrecptr.p->maxp;
+ signal->theData[3] = fragrecptr.p->expandFlag;
+ fragrecptr.p->expandFlag = 2;
+ sendSignal(cownBlockref, GSN_SHRINKCHECK2, signal, 4, JBB);
+ }//if
+ }//if
+ }//if
+ }//if
+ } else {
+ jam(); /* EXPAND PROCESS HANDLING */
+ rootfragrecptr.p->noOfElements++;
+ fragrecptr.p->slack -= operationRecPtr.p->insertDeleteLen;
+ if (fragrecptr.p->slack >= (1u << 31)) {
+ /* IT MEANS THAT IF SLACK < ZERO */
+ if (fragrecptr.p->expandFlag == 0) {
+ jam();
+ fragrecptr.p->expandFlag = 2;
+ signal->theData[0] = fragrecptr.i;
+ signal->theData[1] = fragrecptr.p->p;
+ signal->theData[2] = fragrecptr.p->maxp;
+ sendSignal(cownBlockref, GSN_EXPANDCHECK2, signal, 3, JBB);
+ }//if
+ }//if
+ }//if
+ }
+ return;
+}//Dbacc::execACC_COMMITREQ()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC ABORT REQ ABORT ALL OPERATION OF THE TRANSACTION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+/* ******************--------------------------------------------------------------- */
+/* ACC ABORT REQ ABORT TRANSACTION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACC_ABORTREQ(Signal* signal)
+{
+ jamEntry();
+ accAbortReqLab(signal, true);
+}//Dbacc::execACC_ABORTREQ()
+
+void Dbacc::accAbortReqLab(Signal* signal, bool sendConf)
+{
+ operationRecPtr.i = signal->theData[0];
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ tresult = 0; /* ZFALSE */
+ if ((operationRecPtr.p->transactionstate == ACTIVE) ||
+ (operationRecPtr.p->transactionstate == WAIT_COMMIT_ABORT)) {
+ jam();
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ operationRecPtr.p->transactionstate = ABORT;
+ abortOperation(signal);
+ } else {
+ ndbrequire(operationRecPtr.p->transactionstate == IDLE);
+ jam();
+ }//if
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ if (! sendConf)
+ return;
+ signal->theData[0] = operationRecPtr.p->userptr;
+ sendSignal(operationRecPtr.p->userblockref, GSN_ACC_ABORTCONF, signal, 1, JBB);
+ return;
+}//Dbacc::accAbortReqLab()
+
+/*
+ * Lock or unlock tuple.
+ */
+void Dbacc::execACC_LOCKREQ(Signal* signal)
+{
+ jamEntry();
+ AccLockReq* sig = (AccLockReq*)signal->getDataPtrSend();
+ AccLockReq reqCopy = *sig;
+ AccLockReq* const req = &reqCopy;
+ Uint32 lockOp = (req->requestInfo & 0xFF);
+ if (lockOp == AccLockReq::LockShared ||
+ lockOp == AccLockReq::LockExclusive) {
+ jam();
+ // find table
+ tabptr.i = req->tableId;
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ // find fragment (TUX will know it)
+ if (req->fragPtrI == RNIL) {
+ for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) {
+ jam();
+ if (tabptr.p->fragptrholder[i] != RNIL) {
+ rootfragrecptr.i = tabptr.p->fragptrholder[i];
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->fragmentid[0] == req->fragId) {
+ jam();
+ req->fragPtrI = rootfragrecptr.p->fragmentptr[0];
+ break;
+ }
+ if (rootfragrecptr.p->fragmentid[1] == req->fragId) {
+ jam();
+ req->fragPtrI = rootfragrecptr.p->fragmentptr[1];
+ break;
+ }
+ }
+ }
+ }
+ fragrecptr.i = req->fragPtrI;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ ndbrequire(req->fragId == fragrecptr.p->myfid);
+ // caller must be explicit here
+ ndbrequire(req->accOpPtr == RNIL);
+ // seize operation to hold the lock
+ if (cfreeopRec != RNIL) {
+ jam();
+ seizeOpRec(signal);
+ // init as in ACCSEIZEREQ
+ operationRecPtr.p->userptr = req->userPtr;
+ operationRecPtr.p->userblockref = req->userRef;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+ operationRecPtr.p->transactionstate = IDLE;
+ // do read with lock via ACCKEYREQ
+ Uint32 lockMode = (lockOp == AccLockReq::LockShared) ? 0 : 1;
+ Uint32 opCode = ZSCAN_OP;
+ signal->theData[0] = operationRecPtr.i;
+ signal->theData[1] = fragrecptr.i;
+ signal->theData[2] = opCode | (lockMode << 4) | (1u << 31);
+ signal->theData[3] = req->hashValue;
+ signal->theData[4] = 1; // fake primKeyLen
+ signal->theData[5] = req->transId1;
+ signal->theData[6] = req->transId2;
+ // enter local key in place of PK
+ signal->theData[7] = req->tupAddr;
+ EXECUTE_DIRECT(DBACC, GSN_ACCKEYREQ, signal, 8);
+ // translate the result
+ if (signal->theData[0] < RNIL) {
+ jam();
+ req->returnCode = AccLockReq::Success;
+ req->accOpPtr = operationRecPtr.i;
+ } else if (signal->theData[0] == RNIL) {
+ jam();
+ req->returnCode = AccLockReq::IsBlocked;
+ req->accOpPtr = operationRecPtr.i;
+ } else {
+ ndbrequire(signal->theData[0] == (UintR)-1);
+ releaseOpRec(signal);
+ req->returnCode = AccLockReq::Refused;
+ req->accOpPtr = RNIL;
+ }
+ } else {
+ jam();
+ req->returnCode = AccLockReq::NoFreeOp;
+ }
+ *sig = *req;
+ return;
+ }
+ if (lockOp == AccLockReq::Unlock) {
+ jam();
+ // do unlock via ACC_COMMITREQ (immediate)
+ signal->theData[0] = req->accOpPtr;
+ EXECUTE_DIRECT(DBACC, GSN_ACC_COMMITREQ, signal, 1);
+ releaseOpRec(signal);
+ req->returnCode = AccLockReq::Success;
+ *sig = *req;
+ return;
+ }
+ if (lockOp == AccLockReq::Abort) {
+ jam();
+ // do abort via ACC_ABORTREQ (immediate)
+ signal->theData[0] = req->accOpPtr;
+ accAbortReqLab(signal, false);
+ releaseOpRec(signal);
+ req->returnCode = AccLockReq::Success;
+ *sig = *req;
+ return;
+ }
+ if (lockOp == AccLockReq::AbortWithConf) {
+ jam();
+ // do abort via ACC_ABORTREQ (with conf signal)
+ signal->theData[0] = req->accOpPtr;
+ accAbortReqLab(signal, true);
+ releaseOpRec(signal);
+ req->returnCode = AccLockReq::Success;
+ *sig = *req;
+ return;
+ }
+ ndbrequire(false);
+}
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF EXECUTE OPERATION MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* MODULE: INSERT */
+/* THE FOLLOWING SUBROUTINES ARE ONLY USED BY INSERT_ELEMENT. THIS */
+/* ROUTINE IS THE SOLE INTERFACE TO INSERT ELEMENTS INTO THE INDEX. */
+/* CURRENT USERS ARE INSERT REQUESTS, EXPAND CONTAINER AND SHRINK */
+/* CONTAINER. */
+/* */
+/* THE FOLLOWING SUBROUTINES ARE INCLUDED IN THIS MODULE: */
+/* INSERT_ELEMENT */
+/* INSERT_CONTAINER */
+/* ADDNEWCONTAINER */
+/* GETFREELIST */
+/* INCREASELISTCONT */
+/* SEIZE_LEFTLIST */
+/* SEIZE_RIGHTLIST */
+/* */
+/* THESE ROUTINES ARE ONLY USED BY THIS MODULE AND BY NO ONE ELSE. */
+/* ALSO THE ROUTINES MAKE NO USE OF ROUTINES IN OTHER MODULES. */
+/* TAKE_REC_OUT_OF_FREE_OVERPAGE AND RELEASE_OVERFLOW_REC ARE */
+/* EXCEPTIONS TO THIS RULE. */
+/* */
+/* THE ONLY SHORT-LIVED VARIABLES USED IN OTHER PARTS OF THE BLOCK ARE */
+/* THOSE DEFINED AS INPUT AND OUTPUT IN INSERT_ELEMENT */
+/* SHORT-LIVED VARIABLES INCLUDE TEMPORARY VARIABLES, COMMON VARIABLES */
+/* AND POINTER VARIABLES. */
+/* THE ONLY EXCEPTION TO THIS RULE IS FRAGRECPTR WHICH POINTS TO THE */
+/* FRAGMENT RECORD. THIS IS MORE LESS STATIC ALWAYS DURING A SIGNAL */
+/* EXECUTION. */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* INSERT_ELEMENT */
+/* INPUT: */
+/* IDR_PAGEPTR (POINTER TO THE ACTIVE PAGE REC) */
+/* TIDR_PAGEINDEX (INDEX OF THE CONTAINER) */
+/* TIDR_FORWARD (DIRECTION FORWARD OR BACKWARD) */
+/* TIDR_ELEMHEAD (HEADER OF ELEMENT TO BE INSERTED */
+/* CIDR_KEYS(ARRAY OF TUPLE KEYS) */
+/* CLOCALKEY(ARRAY OF LOCAL KEYS). */
+/* FRAGRECPTR */
+/* IDR_OPERATION_REC_PTR */
+/* TIDR_KEY_LEN */
+/* */
+/* OUTPUT: */
+/* TIDR_PAGEINDEX (PAGE INDEX OF INSERTED ELEMENT) */
+/* IDR_PAGEPTR (PAGE POINTER OF INSERTED ELEMENT) */
+/* TIDR_FORWARD (CONTAINER DIRECTION OF INSERTED ELEMENT) */
+/* NONE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::insertElement(Signal* signal)
+{
+ DirRangePtr inrOverflowrangeptr;
+ DirectoryarrayPtr inrOverflowDirptr;
+ OverflowRecordPtr inrOverflowRecPtr;
+ Page8Ptr inrNewPageptr;
+ Uint32 tinrNextSamePage;
+ Uint32 tinrTmp;
+
+ do {
+ insertContainer(signal);
+ if (tidrResult != ZFALSE) {
+ jam();
+ return;
+ /* INSERTION IS DONE, OR */
+ /* AN ERROR IS DETECTED */
+ }//if
+ if (((tidrContainerhead >> 7) & 0x3) != 0) {
+ tinrNextSamePage = (tidrContainerhead >> 9) & 0x1; /* CHECK BIT FOR CHECKING WHERE */
+ /* THE NEXT CONTAINER IS IN THE SAME PAGE */
+ tidrPageindex = tidrContainerhead & 0x7f; /* NEXT CONTAINER PAGE INDEX 7 BITS */
+ if (((tidrContainerhead >> 7) & 3) == ZLEFT) {
+ jam();
+ tidrForward = ZTRUE;
+ } else if (((tidrContainerhead >> 7) & 3) == ZRIGHT) {
+ jam();
+ tidrForward = cminusOne;
+ } else {
+ ndbrequire(false);
+ return;
+ }//if
+ if (tinrNextSamePage == ZFALSE) {
+ jam(); /* NEXT CONTAINER IS IN AN OVERFLOW PAGE */
+ tinrTmp = idrPageptr.p->word32[tidrContainerptr + 1];
+ inrOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ ptrCheckGuard(inrOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard((tinrTmp >> 8), 256);
+ inrOverflowDirptr.i = inrOverflowrangeptr.p->dirArray[tinrTmp >> 8];
+ ptrCheckGuard(inrOverflowDirptr, cdirarraysize, directoryarray);
+ idrPageptr.i = inrOverflowDirptr.p->pagep[tinrTmp & 0xff];
+ ptrCheckGuard(idrPageptr, cpagesize, page8);
+ }//if
+ ndbrequire(tidrPageindex < ZEMPTYLIST);
+ } else {
+ break;
+ }//if
+ } while (1);
+ gflPageptr.p = idrPageptr.p;
+ getfreelist(signal);
+ if (tgflPageindex == ZEMPTYLIST) {
+ jam();
+ /* NO FREE BUFFER IS FOUND */
+ if (fragrecptr.p->firstOverflowRec == RNIL) {
+ jam();
+ allocOverflowPage(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ }//if
+ inrOverflowRecPtr.i = fragrecptr.p->firstOverflowRec;
+ ptrCheckGuard(inrOverflowRecPtr, coverflowrecsize, overflowRecord);
+ inrNewPageptr.i = inrOverflowRecPtr.p->overpage;
+ ptrCheckGuard(inrNewPageptr, cpagesize, page8);
+ gflPageptr.p = inrNewPageptr.p;
+ getfreelist(signal);
+ ndbrequire(tgflPageindex != ZEMPTYLIST);
+ tancNext = 0;
+ } else {
+ jam();
+ inrNewPageptr = idrPageptr;
+ tancNext = 1;
+ }//if
+ tslUpdateHeader = ZTRUE;
+ tslPageindex = tgflPageindex;
+ slPageptr.p = inrNewPageptr.p;
+ if (tgflBufType == ZLEFT) {
+ seizeLeftlist(signal);
+ tidrForward = ZTRUE;
+ } else {
+ seizeRightlist(signal);
+ tidrForward = cminusOne;
+ }//if
+ tancPageindex = tgflPageindex;
+ tancPageid = inrNewPageptr.p->word32[ZPOS_PAGE_ID];
+ tancBufType = tgflBufType;
+ tancContainerptr = tidrContainerptr;
+ ancPageptr.p = idrPageptr.p;
+ addnewcontainer(signal);
+
+ idrPageptr = inrNewPageptr;
+ tidrPageindex = tgflPageindex;
+ insertContainer(signal);
+ ndbrequire(tidrResult == ZTRUE);
+}//Dbacc::insertElement()
+
+/* --------------------------------------------------------------------------------- */
+/* INSERT_CONTAINER */
+/* INPUT: */
+/* IDR_PAGEPTR (POINTER TO THE ACTIVE PAGE REC) */
+/* TIDR_PAGEINDEX (INDEX OF THE CONTAINER) */
+/* TIDR_FORWARD (DIRECTION FORWARD OR BACKWARD) */
+/* TIDR_ELEMHEAD (HEADER OF ELEMENT TO BE INSERTED */
+/* CKEYS(ARRAY OF TUPLE KEYS) */
+/* CLOCALKEY(ARRAY 0F LOCAL KEYS). */
+/* TIDR_KEY_LEN */
+/* FRAGRECPTR */
+/* IDR_OPERATION_REC_PTR */
+/* OUTPUT: */
+/* TIDR_RESULT (ZTRUE FOR SUCCESS AND ZFALSE OTHERWISE) */
+/* TIDR_CONTAINERHEAD (HEADER OF CONTAINER) */
+/* TIDR_CONTAINERPTR (POINTER TO CONTAINER HEADER) */
+/* */
+/* DESCRIPTION: */
+/* THE FREE AREA OF THE CONTAINER WILL BE CALCULATED. IF IT IS */
+/* LARGER THAN OR EQUAL THE ELEMENT LENGTH. THE ELEMENT WILL BE */
+/* INSERT IN THE CONTAINER AND CONTAINER HEAD WILL BE UPDATED. */
+/* THIS ROUTINE ALWAYS DEALS WITH ONLY ONE CONTAINER AND DO NEVER */
+/* START ANYTHING OUTSIDE OF THIS CONTAINER. */
+/* */
+/* SHORT FORM: IDR */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::insertContainer(Signal* signal)
+{
+ Uint32 tidrContainerlen;
+ Uint32 tidrConfreelen;
+ Uint32 tidrNextSide;
+ Uint32 tidrNextConLen;
+ Uint32 tidrIndex;
+ Uint32 tidrInputIndex;
+ Uint32 tidrContLen;
+ Uint32 guard26;
+
+ tidrResult = ZFALSE;
+ tidrContainerptr = (tidrPageindex << ZSHIFT_PLUS) - (tidrPageindex << ZSHIFT_MINUS);
+ tidrContainerptr = tidrContainerptr + ZHEAD_SIZE;
+ /* --------------------------------------------------------------------------------- */
+ /* CALCULATE THE POINTER TO THE ELEMENT TO BE INSERTED AND THE POINTER TO THE */
+ /* CONTAINER HEADER OF THE OTHER SIDE OF THE BUFFER. */
+ /* --------------------------------------------------------------------------------- */
+ if (tidrForward == ZTRUE) {
+ jam();
+ tidrNextSide = tidrContainerptr + (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ arrGuard(tidrNextSide + 1, 2048);
+ tidrContainerhead = idrPageptr.p->word32[tidrContainerptr];
+ tidrContainerlen = tidrContainerhead >> 26;
+ tidrIndex = tidrContainerptr + tidrContainerlen;
+ } else {
+ jam();
+ tidrNextSide = tidrContainerptr;
+ tidrContainerptr = tidrContainerptr + (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ arrGuard(tidrContainerptr + 1, 2048);
+ tidrContainerhead = idrPageptr.p->word32[tidrContainerptr];
+ tidrContainerlen = tidrContainerhead >> 26;
+ tidrIndex = (tidrContainerptr - tidrContainerlen) + (ZCON_HEAD_SIZE - 1);
+ }//if
+ if (tidrContainerlen > (ZBUF_SIZE - 3)) {
+ return;
+ }//if
+ tidrConfreelen = ZBUF_SIZE - tidrContainerlen;
+ /* --------------------------------------------------------------------------------- */
+ /* WE CALCULATE THE TOTAL LENGTH THE CONTAINER CAN EXPAND TO */
+ /* THIS INCLUDES THE OTHER SIDE OF THE BUFFER IF POSSIBLE TO EXPAND THERE. */
+ /* --------------------------------------------------------------------------------- */
+ if (((tidrContainerhead >> 10) & 1) == 0) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE NOT EXPANDED TO THE ENTIRE BUFFER YET. WE CAN THUS READ THE OTHER */
+ /* SIDE'S CONTAINER HEADER TO READ HIS LENGTH. */
+ /* --------------------------------------------------------------------------------- */
+ tidrNextConLen = idrPageptr.p->word32[tidrNextSide] >> 26;
+ tidrConfreelen = tidrConfreelen - tidrNextConLen;
+ if (tidrConfreelen > ZBUF_SIZE) {
+ ndbrequire(false);
+ /* --------------------------------------------------------------------------------- */
+ /* THE BUFFERS ARE PLACED ON TOP OF EACH OTHER. THIS SHOULD NEVER OCCUR. */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ }//if
+ } else {
+ jam();
+ tidrNextConLen = 1; /* INDICATE OTHER SIDE IS NOT PART OF FREE LIST */
+ }//if
+ if (tidrConfreelen < fragrecptr.p->elementLength) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE CONTAINER COULD NOT BE EXPANDED TO FIT THE NEW ELEMENT. WE HAVE TO */
+ /* RETURN AND FIND A NEW CONTAINER TO INSERT IT INTO. */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ }//if
+ tidrContainerlen = tidrContainerlen + fragrecptr.p->elementLength;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = idrPageptr.p;
+ cundoElemIndex = tidrContainerptr;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ if (tidrNextConLen == 0) {
+ /* EACH SIDE OF THE BUFFER WHICH BELONG TO A FREE */
+ /* LIST, HAS ZERO AS LENGTH. */
+ if (tidrContainerlen > ZUP_LIMIT) {
+ dbgWord32(idrPageptr, tidrContainerptr, idrPageptr.p->word32[tidrContainerptr] | (1 << 10));
+ idrPageptr.p->word32[tidrContainerptr] = idrPageptr.p->word32[tidrContainerptr] | (1 << 10);
+ tslUpdateHeader = ZFALSE;
+ tslPageindex = tidrPageindex;
+ slPageptr.p = idrPageptr.p;
+ if (tidrForward == ZTRUE) {
+ jam();
+ seizeRightlist(signal); /* REMOVE THE RIGHT SIDE OF THE BUFFER FROM THE LIST */
+ } else {
+ jam();
+ /* OF THE FREE CONTAINERS */
+ seizeLeftlist(signal); /* REMOVE THE LEFT SIDE OF THE BUFFER FROM THE LIST */
+ }//if
+ }//if
+ }//if
+ /* OF THE FREE CONTAINERS */
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE NOW FOUND A FREE SPOT IN THE CURRENT CONTAINER. WE INSERT THE */
+ /* ELEMENT HERE. THE ELEMENT CONTAINS A HEADER, A LOCAL KEY AND A TUPLE KEY. */
+ /* BEFORE INSERTING THE ELEMENT WE WILL UPDATE THE OPERATION RECORD WITH THE */
+ /* DATA CONCERNING WHERE WE INSERTED THE ELEMENT. THIS MAKES IT EASY TO FIND */
+ /* THIS INFORMATION WHEN WE RETURN TO UPDATE THE LOCAL KEY OR RETURN TO COMMIT */
+ /* OR ABORT THE INSERT. IF NO OPERATION RECORD EXIST IT MEANS THAT WE ARE */
+ /* PERFORMING THIS AS A PART OF THE EXPAND OR SHRINK PROCESS. */
+ /* --------------------------------------------------------------------------------- */
+ if (idrOperationRecPtr.i != RNIL) {
+ jam();
+ idrOperationRecPtr.p->elementIsforward = tidrForward;
+ idrOperationRecPtr.p->elementPage = idrPageptr.i;
+ idrOperationRecPtr.p->elementContainer = tidrContainerptr;
+ idrOperationRecPtr.p->elementPointer = tidrIndex;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* WE CHOOSE TO UNDO LOG INSERTS BY WRITING THE BEFORE VALUE TO THE UNDO LOG. */
+ /* WE COULD ALSO HAVE DONE THIS BY WRITING THIS BEFORE VALUE WHEN DELETING */
+ /* ELEMENTS. WE CHOOSE TO PUT IT HERE SINCE WE THEREBY ENSURE THAT WE ALWAYS */
+ /* UNDO LOG ALL WRITES TO PAGE MEMORY. IT SHOULD BE EASIER TO MAINTAIN SUCH A */
+ /* STRUCTURE. IT IS RATHER DIFFICULT TO MAINTAIN A LOGICAL STRUCTURE WHERE */
+ /* DELETES ARE INSERTS AND INSERTS ARE PURELY DELETES. */
+ /* --------------------------------------------------------------------------------- */
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (tidrForward == ZTRUE) {
+ cundoElemIndex = tidrIndex;
+ } else {
+ cundoElemIndex = (tidrIndex + 1) - fragrecptr.p->elementLength;
+ }//if
+ cundoinfolength = fragrecptr.p->elementLength;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(idrPageptr, tidrIndex, tidrElemhead);
+ idrPageptr.p->word32[tidrIndex] = tidrElemhead; /* INSERTS THE HEAD OF THE ELEMENT */
+ tidrIndex += tidrForward;
+ guard26 = fragrecptr.p->localkeylen - 1;
+ arrGuard(guard26, 2);
+ for (tidrInputIndex = 0; tidrInputIndex <= guard26; tidrInputIndex++) {
+ dbgWord32(idrPageptr, tidrIndex, clocalkey[tidrInputIndex]);
+ arrGuard(tidrIndex, 2048);
+ idrPageptr.p->word32[tidrIndex] = clocalkey[tidrInputIndex]; /* INSERTS LOCALKEY */
+ tidrIndex += tidrForward;
+ }//for
+ tidrContLen = idrPageptr.p->word32[tidrContainerptr] << 6;
+ tidrContLen = tidrContLen >> 6;
+ dbgWord32(idrPageptr, tidrContainerptr, (tidrContainerlen << 26) | tidrContLen);
+ idrPageptr.p->word32[tidrContainerptr] = (tidrContainerlen << 26) | tidrContLen;
+ tidrResult = ZTRUE;
+}//Dbacc::insertContainer()
+
+/* --------------------------------------------------------------------------------- */
+/* ADDNEWCONTAINER */
+/* INPUT: */
+/* TANC_CONTAINERPTR */
+/* ANC_PAGEPTR */
+/* TANC_NEXT */
+/* TANC_PAGEINDEX */
+/* TANC_BUF_TYPE */
+/* TANC_PAGEID */
+/* OUTPUT: */
+/* NONE */
+/* */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::addnewcontainer(Signal* signal)
+{
+ Uint32 tancTmp1;
+
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tancContainerptr;
+ datapageptr.p = ancPageptr.p;
+ cundoinfolength = 2;
+ undoWritingProcess(signal); /* WHEN UNDO PROCESS HAS STARTED, */
+ }//if
+ /* THE OLD DATA IS STORED ON AN UNDO PAGE */
+ /* --------------------------------------------------------------------------------- */
+ /* KEEP LENGTH INFORMATION IN BIT 26-31. */
+ /* SET BIT 9 INDICATING IF NEXT BUFFER IN THE SAME PAGE USING TANC_NEXT. */
+ /* SET TYPE OF NEXT CONTAINER IN BIT 7-8. */
+ /* SET PAGE INDEX OF NEXT CONTAINER IN BIT 0-6. */
+ /* KEEP INDICATOR OF OWNING OTHER SIDE OF BUFFER IN BIT 10. */
+ /* --------------------------------------------------------------------------------- */
+ tancTmp1 = ancPageptr.p->word32[tancContainerptr] >> 10;
+ tancTmp1 = tancTmp1 << 1;
+ tancTmp1 = tancTmp1 | tancNext;
+ tancTmp1 = tancTmp1 << 2;
+ tancTmp1 = tancTmp1 | tancBufType; /* TYPE OF THE NEXT CONTAINER */
+ tancTmp1 = tancTmp1 << 7;
+ tancTmp1 = tancTmp1 | tancPageindex;
+ dbgWord32(ancPageptr, tancContainerptr, tancTmp1);
+ ancPageptr.p->word32[tancContainerptr] = tancTmp1; /* HEAD OF THE CONTAINER IS UPDATED */
+ dbgWord32(ancPageptr, tancContainerptr + 1, tancPageid);
+ ancPageptr.p->word32[tancContainerptr + 1] = tancPageid;
+}//Dbacc::addnewcontainer()
+
+/* --------------------------------------------------------------------------------- */
+/* GETFREELIST */
+/* INPUT: */
+/* GFL_PAGEPTR (POINTER TO A PAGE RECORD). */
+/* OUTPUT: */
+/* TGFL_PAGEINDEX(POINTER TO A FREE BUFFER IN THE FREEPAGE), AND */
+/* TGFL_BUF_TYPE( TYPE OF THE FREE BUFFER). */
+/* DESCRIPTION: SEARCHS IN THE FREE LIST OF THE FREE BUFFER IN THE PAGE HEAD */
+/* (WORD32(1)),AND RETURN ADDRESS OF A FREE BUFFER OR NIL. */
+/* THE FREE BUFFER CAN BE A RIGHT CONTAINER OR A LEFT ONE */
+/* THE KIND OF THE CONTAINER IS NOTED BY TGFL_BUF_TYPE. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::getfreelist(Signal* signal)
+{
+ Uint32 tgflTmp;
+
+ tgflTmp = gflPageptr.p->word32[ZPOS_EMPTY_LIST];
+ tgflPageindex = (tgflTmp >> 7) & 0x7f; /* LEFT FREE LIST */
+ tgflBufType = ZLEFT;
+ if (tgflPageindex == ZEMPTYLIST) {
+ jam();
+ tgflPageindex = tgflTmp & 0x7f; /* RIGHT FREE LIST */
+ tgflBufType = ZRIGHT;
+ }//if
+ ndbrequire(tgflPageindex <= ZEMPTYLIST);
+}//Dbacc::getfreelist()
+
+/* --------------------------------------------------------------------------------- */
+/* INCREASELISTCONT */
+/* INPUT: */
+/* ILC_PAGEPTR PAGE POINTER TO INCREASE NUMBER OF CONTAINERS IN */
+/* A CONTAINER OF AN OVERFLOW PAGE (FREEPAGEPTR) IS ALLOCATED, NR OF */
+/* ALLOCATED CONTAINER HAVE TO BE INCRESE BY ONE . */
+/* IF THE NUMBER OF ALLOCATED CONTAINERS IS ABOVE THE FREE LIMIT WE WILL */
+/* REMOVE THE PAGE FROM THE FREE LIST. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::increaselistcont(Signal* signal)
+{
+ OverflowRecordPtr ilcOverflowRecPtr;
+
+ dbgWord32(ilcPageptr, ZPOS_ALLOC_CONTAINERS, ilcPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] + 1);
+ ilcPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] = ilcPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] + 1;
+ if (ilcPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] > ZFREE_LIMIT) {
+ if (ilcPageptr.p->word32[ZPOS_OVERFLOWREC] != RNIL) {
+ jam();
+ ilcOverflowRecPtr.i = ilcPageptr.p->word32[ZPOS_OVERFLOWREC];
+ dbgWord32(ilcPageptr, ZPOS_OVERFLOWREC, RNIL);
+ ilcPageptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+ ptrCheckGuard(ilcOverflowRecPtr, coverflowrecsize, overflowRecord);
+ tfoOverflowRecPtr = ilcOverflowRecPtr;
+ takeRecOutOfFreeOverpage(signal);
+ rorOverflowRecPtr = ilcOverflowRecPtr;
+ releaseOverflowRec(signal);
+ }//if
+ }//if
+}//Dbacc::increaselistcont()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_LEFTLIST */
+/* INPUT: */
+/* TSL_PAGEINDEX PAGE INDEX OF CONTAINER TO SEIZE */
+/* SL_PAGEPTR PAGE POINTER OF CONTAINER TO SEIZE */
+/* TSL_UPDATE_HEADER SHOULD WE UPDATE THE CONTAINER HEADER */
+/* */
+/* OUTPUT: */
+/* NONE */
+/* DESCRIPTION: THE BUFFER NOTED BY TSL_PAGEINDEX WILL BE REMOVED FROM THE */
+/* LIST OF LEFT FREE CONTAINER, IN THE HEADER OF THE PAGE */
+/* (FREEPAGEPTR). PREVIOUS AND NEXT BUFFER OF REMOVED BUFFER */
+/* WILL BE UPDATED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeLeftlist(Signal* signal)
+{
+ Uint32 tsllTmp1;
+ Uint32 tsllNewHead;
+ Uint32 tsllHeadIndex;
+ Uint32 tsllTmp;
+
+ tsllHeadIndex = ((tslPageindex << ZSHIFT_PLUS) - (tslPageindex << ZSHIFT_MINUS)) + ZHEAD_SIZE;
+ arrGuard(tsllHeadIndex + 1, 2048);
+ tslNextfree = slPageptr.p->word32[tsllHeadIndex];
+ tslPrevfree = slPageptr.p->word32[tsllHeadIndex + 1];
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = slPageptr.p;
+ cundoElemIndex = tsllHeadIndex;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = ZPOS_EMPTY_LIST;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (tslPrevfree == ZEMPTYLIST) {
+ jam();
+ /* UPDATE FREE LIST OF LEFT CONTAINER IN PAGE HEAD */
+ tsllTmp1 = slPageptr.p->word32[ZPOS_EMPTY_LIST];
+ tsllTmp = tsllTmp1 & 0x7f;
+ tsllTmp1 = (tsllTmp1 >> 14) << 14;
+ tsllTmp1 = (tsllTmp1 | (tslNextfree << 7)) | tsllTmp;
+ dbgWord32(slPageptr, ZPOS_EMPTY_LIST, tsllTmp1);
+ slPageptr.p->word32[ZPOS_EMPTY_LIST] = tsllTmp1;
+ } else {
+ ndbrequire(tslPrevfree < ZEMPTYLIST);
+ jam();
+ tsllTmp = ((tslPrevfree << ZSHIFT_PLUS) - (tslPrevfree << ZSHIFT_MINUS)) + ZHEAD_SIZE;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tsllTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(slPageptr, tsllTmp, tslNextfree);
+ slPageptr.p->word32[tsllTmp] = tslNextfree;
+ }//if
+ if (tslNextfree < ZEMPTYLIST) {
+ jam();
+ tsllTmp = (((tslNextfree << ZSHIFT_PLUS) - (tslNextfree << ZSHIFT_MINUS)) + ZHEAD_SIZE) + 1;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tsllTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(slPageptr, tsllTmp, tslPrevfree);
+ slPageptr.p->word32[tsllTmp] = tslPrevfree;
+ } else {
+ ndbrequire(tslNextfree == ZEMPTYLIST);
+ jam();
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* IF WE ARE UPDATING THE HEADER WE ARE CREATING A NEW CONTAINER IN THE PAGE. */
+ /* TO BE ABLE TO FIND ALL LOCKED ELEMENTS WE KEEP ALL CONTAINERS IN LINKED */
+ /* LISTS IN THE PAGE. */
+ /* */
+ /* ZPOS_EMPTY_LIST CONTAINS A NEXT POINTER IN BIT 16-22 THAT REFERS TO THE */
+ /* FIRST CONTAINER IN A LIST OF USED RIGHT CONTAINERS IN THE PAGE. */
+ /* ZPOS_EMPTY_LIST CONTAINS A NEXT POINTER IN BIT 23-29 THAT REFERS TO THE */
+ /* FIRST CONTAINER IN A LIST OF USED LEFT CONTAINERS IN THE PAGE. */
+ /* EACH CONTAINER IN THE LIST CONTAINS A NEXT POINTER IN BIT 11-17 AND IT */
+ /* CONTAINS A PREVIOUS POINTER IN BIT 18-24. */
+ /* WE ALSO SET BIT 25 TO INDICATE THAT IT IS A CONTAINER HEADER. */
+ /* --------------------------------------------------------------------------------- */
+ if (tslUpdateHeader == ZTRUE) {
+ jam();
+ tslNextfree = (slPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
+ tsllNewHead = ZCON_HEAD_SIZE;
+ tsllNewHead = ((tsllNewHead << 8) + ZEMPTYLIST) + (1 << 7);
+ tsllNewHead = (tsllNewHead << 7) + tslNextfree;
+ tsllNewHead = tsllNewHead << 11;
+ dbgWord32(slPageptr, tsllHeadIndex, tsllNewHead);
+ slPageptr.p->word32[tsllHeadIndex] = tsllNewHead;
+ tsllTmp = slPageptr.p->word32[ZPOS_EMPTY_LIST] & 0xc07fffff;
+ tsllTmp = tsllTmp | (tslPageindex << 23);
+ dbgWord32(slPageptr, ZPOS_EMPTY_LIST, tsllTmp);
+ slPageptr.p->word32[ZPOS_EMPTY_LIST] = tsllTmp;
+ if (tslNextfree < ZEMPTYLIST) {
+ jam();
+ tsllTmp = ((tslNextfree << ZSHIFT_PLUS) - (tslNextfree << ZSHIFT_MINUS)) + ZHEAD_SIZE;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tsllTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ tsllTmp1 = slPageptr.p->word32[tsllTmp] & 0xfe03ffff;
+ tsllTmp1 = tsllTmp1 | (tslPageindex << 18);
+ dbgWord32(slPageptr, tsllTmp, tsllTmp1);
+ slPageptr.p->word32[tsllTmp] = tsllTmp1;
+ } else {
+ ndbrequire(tslNextfree == ZEMPTYLIST);
+ jam();
+ }//if
+ }//if
+ ilcPageptr.p = slPageptr.p;
+ increaselistcont(signal);
+}//Dbacc::seizeLeftlist()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_RIGHTLIST */
+/* DESCRIPTION: THE BUFFER NOTED BY TSL_PAGEINDEX WILL BE REMOVED FROM THE */
+/* LIST OF RIGHT FREE CONTAINER, IN THE HEADER OF THE PAGE */
+/* (SL_PAGEPTR). PREVIOUS AND NEXT BUFFER OF REMOVED BUFFER */
+/* WILL BE UPDATED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeRightlist(Signal* signal)
+{
+ Uint32 tsrlTmp1;
+ Uint32 tsrlNewHead;
+ Uint32 tsrlHeadIndex;
+ Uint32 tsrlTmp;
+
+ tsrlHeadIndex = ((tslPageindex << ZSHIFT_PLUS) - (tslPageindex << ZSHIFT_MINUS)) + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ arrGuard(tsrlHeadIndex + 1, 2048);
+ tslNextfree = slPageptr.p->word32[tsrlHeadIndex];
+ tslPrevfree = slPageptr.p->word32[tsrlHeadIndex + 1];
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = slPageptr.p;
+ cundoElemIndex = tsrlHeadIndex;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = ZPOS_EMPTY_LIST;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (tslPrevfree == ZEMPTYLIST) {
+ jam();
+ tsrlTmp = slPageptr.p->word32[ZPOS_EMPTY_LIST];
+ dbgWord32(slPageptr, ZPOS_EMPTY_LIST, ((tsrlTmp >> 7) << 7) | tslNextfree);
+ slPageptr.p->word32[ZPOS_EMPTY_LIST] = ((tsrlTmp >> 7) << 7) | tslNextfree;
+ } else {
+ ndbrequire(tslPrevfree < ZEMPTYLIST);
+ jam();
+ tsrlTmp = ((tslPrevfree << ZSHIFT_PLUS) - (tslPrevfree << ZSHIFT_MINUS)) + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tsrlTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(slPageptr, tsrlTmp, tslNextfree);
+ slPageptr.p->word32[tsrlTmp] = tslNextfree;
+ }//if
+ if (tslNextfree < ZEMPTYLIST) {
+ jam();
+ tsrlTmp = ((tslNextfree << ZSHIFT_PLUS) - (tslNextfree << ZSHIFT_MINUS)) + ((ZHEAD_SIZE + ZBUF_SIZE) - (ZCON_HEAD_SIZE - 1));
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ cundoElemIndex = tsrlTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(slPageptr, tsrlTmp, tslPrevfree);
+ slPageptr.p->word32[tsrlTmp] = tslPrevfree;
+ } else {
+ ndbrequire(tslNextfree == ZEMPTYLIST);
+ jam();
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* IF WE ARE UPDATING THE HEADER WE ARE CREATING A NEW CONTAINER IN THE PAGE. */
+ /* TO BE ABLE TO FIND ALL LOCKED ELEMENTS WE KEEP ALL CONTAINERS IN LINKED */
+ /* LISTS IN THE PAGE. */
+ /* */
+ /* ZPOS_EMPTY_LIST CONTAINS A NEXT POINTER IN BIT 16-22 THAT REFERS TO THE */
+ /* FIRST CONTAINER IN A LIST OF USED RIGHT CONTAINERS IN THE PAGE. */
+ /* ZPOS_EMPTY_LIST CONTAINS A NEXT POINTER IN BIT 23-29 THAT REFERS TO THE */
+ /* FIRST CONTAINER IN A LIST OF USED LEFT CONTAINERS IN THE PAGE. */
+ /* EACH CONTAINER IN THE LIST CONTAINS A NEXT POINTER IN BIT 11-17 AND IT */
+ /* CONTAINS A PREVIOUS POINTER IN BIT 18-24. */
+ /* --------------------------------------------------------------------------------- */
+ if (tslUpdateHeader == ZTRUE) {
+ jam();
+ tslNextfree = (slPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
+ tsrlNewHead = ZCON_HEAD_SIZE;
+ tsrlNewHead = ((tsrlNewHead << 8) + ZEMPTYLIST) + (1 << 7);
+ tsrlNewHead = (tsrlNewHead << 7) + tslNextfree;
+ tsrlNewHead = tsrlNewHead << 11;
+ dbgWord32(slPageptr, tsrlHeadIndex, tsrlNewHead);
+ slPageptr.p->word32[tsrlHeadIndex] = tsrlNewHead;
+ tsrlTmp = slPageptr.p->word32[ZPOS_EMPTY_LIST] & 0xff80ffff;
+ dbgWord32(slPageptr, ZPOS_EMPTY_LIST, tsrlTmp | (tslPageindex << 16));
+ slPageptr.p->word32[ZPOS_EMPTY_LIST] = tsrlTmp | (tslPageindex << 16);
+ if (tslNextfree < ZEMPTYLIST) {
+ jam();
+ tsrlTmp = ((tslNextfree << ZSHIFT_PLUS) - (tslNextfree << ZSHIFT_MINUS)) + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = tsrlTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ tsrlTmp1 = slPageptr.p->word32[tsrlTmp] & 0xfe03ffff;
+ dbgWord32(slPageptr, tsrlTmp, tsrlTmp1 | (tslPageindex << 18));
+ slPageptr.p->word32[tsrlTmp] = tsrlTmp1 | (tslPageindex << 18);
+ } else {
+ ndbrequire(tslNextfree == ZEMPTYLIST);
+ jam();
+ }//if
+ }//if
+ ilcPageptr.p = slPageptr.p;
+ increaselistcont(signal);
+}//Dbacc::seizeRightlist()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF INSERT_ELEMENT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* MODULE: GET_ELEMENT */
+/* THE FOLLOWING SUBROUTINES ARE ONLY USED BY GET_ELEMENT AND */
+/* GETDIRINDEX. THIS ROUTINE IS THE SOLE INTERFACE TO GET ELEMENTS */
+/* FROM THE INDEX. CURRENT USERS ARE ALL REQUESTS AND EXECUTE UNDO LOG */
+/* */
+/* THE FOLLOWING SUBROUTINES ARE INCLUDED IN THIS MODULE: */
+/* GET_ELEMENT */
+/* GET_DIRINDEX */
+/* SEARCH_LONG_KEY */
+/* */
+/* THESE ROUTINES ARE ONLY USED BY THIS MODULE AND BY NO ONE ELSE. */
+/* ALSO THE ROUTINES MAKE NO USE OF ROUTINES IN OTHER MODULES. */
+/* THE ONLY SHORT-LIVED VARIABLES USED IN OTHER PARTS OF THE BLOCK ARE */
+/* THOSE DEFINED AS INPUT AND OUTPUT IN GET_ELEMENT AND GETDIRINDEX */
+/* SHORT-LIVED VARIABLES INCLUDE TEMPORARY VARIABLES, COMMON VARIABLES */
+/* AND POINTER VARIABLES. */
+/* THE ONLY EXCEPTION TO THIS RULE IS FRAGRECPTR WHICH POINTS TO THE */
+/* FRAGMENT RECORD. THIS IS MORE LESS STATIC ALWAYS DURING A SIGNAL */
+/* EXECUTION. */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* GETDIRINDEX */
+/* SUPPORT ROUTINE FOR INSERT ELEMENT, GET ELEMENT AND COMMITDELETE */
+/* INPUT:FRAGRECPTR ( POINTER TO THE ACTIVE FRAGMENT REC) */
+/* OPERATION_REC_PTR (POINTER TO THE OPERATION REC). */
+/* */
+/* OUTPUT:GDI_PAGEPTR ( POINTER TO THE PAGE OF THE ELEMENT) */
+/* TGDI_PAGEINDEX ( INDEX OF THE ELEMENT IN THE PAGE). */
+/* */
+/* DESCRIPTION: CHECK THE HASH VALUE OF THE OPERATION REC AND CALCULATE THE */
+/* THE ADDRESS OF THE ELEMENT IN THE HASH TABLE,(GDI_PAGEPTR, */
+/* TGDI_PAGEINDEX) ACCORDING TO LH3. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::getdirindex(Signal* signal)
+{
+ DirRangePtr gdiDirRangePtr;
+ DirectoryarrayPtr gdiDirptr;
+ Uint32 tgdiTmp;
+ Uint32 tgdiAddress;
+
+ tgdiTmp = fragrecptr.p->k + fragrecptr.p->lhfragbits; /* OBS K = 6 */
+ tgdiPageindex = operationRecPtr.p->hashValue & ((1 << fragrecptr.p->k) - 1);
+ tgdiTmp = operationRecPtr.p->hashValue >> tgdiTmp;
+ tgdiTmp = (tgdiTmp << fragrecptr.p->k) | tgdiPageindex;
+ tgdiAddress = tgdiTmp & fragrecptr.p->maxp;
+ gdiDirRangePtr.i = fragrecptr.p->directory;
+ ptrCheckGuard(gdiDirRangePtr, cdirrangesize, dirRange);
+ if (tgdiAddress < fragrecptr.p->p) {
+ jam();
+ tgdiAddress = tgdiTmp & ((fragrecptr.p->maxp << 1) | 1);
+ }//if
+ tgdiTmp = tgdiAddress >> fragrecptr.p->k;
+ arrGuard((tgdiTmp >> 8), 256);
+ gdiDirptr.i = gdiDirRangePtr.p->dirArray[tgdiTmp >> 8];
+ ptrCheckGuard(gdiDirptr, cdirarraysize, directoryarray);
+ gdiPageptr.i = gdiDirptr.p->pagep[tgdiTmp & 0xff]; /* DIRECTORY INDEX OF SEND BUCKET PAGE */
+ ptrCheckGuard(gdiPageptr, cpagesize, page8);
+}//Dbacc::getdirindex()
+
+Uint32
+Dbacc::readTablePk(Uint32 localkey1)
+{
+ Uint32 tableId = fragrecptr.p->myTableId;
+ Uint32 fragId = fragrecptr.p->myfid;
+ Uint32 fragPageId = localkey1 >> MAX_TUPLES_BITS;
+ Uint32 pageIndex = localkey1 & ((1 << MAX_TUPLES_BITS ) - 1);
+#ifdef VM_TRACE
+ memset(ckeys, 0x1f, (fragrecptr.p->keyLength * MAX_XFRM_MULTIPLY) << 2);
+#endif
+ int ret = c_tup->accReadPk(tableId, fragId, fragPageId, pageIndex, ckeys, true);
+ ndbrequire(ret > 0);
+ return ret;
+}
+
+/* --------------------------------------------------------------------------------- */
+/* GET_ELEMENT */
+/* INPUT: */
+/* OPERATION_REC_PTR */
+/* FRAGRECPTR */
+/* OUTPUT: */
+/* TGE_RESULT RESULT SUCCESS = ZTRUE OTHERWISE ZFALSE */
+/* TGE_LOCKED LOCK INFORMATION IF SUCCESSFUL RESULT */
+/* GE_PAGEPTR PAGE POINTER OF FOUND ELEMENT */
+/* TGE_CONTAINERPTR CONTAINER INDEX OF FOUND ELEMENT */
+/* TGE_ELEMENTPTR ELEMENT INDEX OF FOUND ELEMENT */
+/* TGE_FORWARD DIRECTION OF CONTAINER WHERE ELEMENT FOUND */
+/* */
+/* DESCRIPTION: THE SUBROUTIN GOES THROUGH ALL CONTAINERS OF THE ACTIVE */
+/* BUCKET, AND SERCH FOR ELEMENT.THE PRIMARY KEYS WHICH IS SAVED */
+/* IN THE OPERATION REC ARE THE CHECK ITEMS IN THE SEARCHING. */
+/* --------------------------------------------------------------------------------- */
+
+#if __ia64 == 1
+#if __INTEL_COMPILER == 810
+int ndb_acc_ia64_icc810_dummy_var = 0;
+void ndb_acc_ia64_icc810_dummy_func()
+{
+ ndb_acc_ia64_icc810_dummy_var++;
+}
+#endif
+#endif
+
+void Dbacc::getElement(Signal* signal)
+{
+ DirRangePtr geOverflowrangeptr;
+ DirectoryarrayPtr geOverflowDirptr;
+ OperationrecPtr geTmpOperationRecPtr;
+ Uint32 tgeElementHeader;
+ Uint32 tgeElemStep;
+ Uint32 tgeContainerhead;
+ Uint32 tgePageindex;
+ Uint32 tgeActivePageDir;
+ Uint32 tgeNextptrtype;
+ register Uint32 tgeKeyptr;
+ register Uint32 tgeRemLen;
+ register Uint32 TelemLen = fragrecptr.p->elementLength;
+ register Uint32* Tkeydata = (Uint32*)&signal->theData[7];
+
+ getdirindex(signal);
+ tgePageindex = tgdiPageindex;
+ gePageptr = gdiPageptr;
+ tgeResult = ZFALSE;
+ /*
+ * The value seached is
+ * - table key for ACCKEYREQ, stored in TUP
+ * - local key (1 word) for ACC_LOCKREQ and UNDO, stored in ACC
+ */
+ const bool searchLocalKey =
+ operationRecPtr.p->isAccLockReq || operationRecPtr.p->isUndoLogReq;
+
+ ndbrequire(TelemLen == ZELEM_HEAD_SIZE + fragrecptr.p->localkeylen);
+ tgeNextptrtype = ZLEFT;
+ tgeLocked = 0;
+
+ const Uint32 tmp = fragrecptr.p->k + fragrecptr.p->lhfragbits;
+ const Uint32 opHashValuePart = (operationRecPtr.p->hashValue >> tmp) &0xFFFF;
+ do {
+ tgeContainerptr = (tgePageindex << ZSHIFT_PLUS) - (tgePageindex << ZSHIFT_MINUS);
+ if (tgeNextptrtype == ZLEFT) {
+ jam();
+ tgeContainerptr = tgeContainerptr + ZHEAD_SIZE;
+ tgeElementptr = tgeContainerptr + ZCON_HEAD_SIZE;
+ tgeKeyptr = (tgeElementptr + ZELEM_HEAD_SIZE) + fragrecptr.p->localkeylen;
+ tgeElemStep = TelemLen;
+ tgeForward = 1;
+ if (tgeContainerptr >= 2048) { ACCKEY_error(4); return;}
+ tgeRemLen = gePageptr.p->word32[tgeContainerptr] >> 26;
+ if ((tgeContainerptr + tgeRemLen - 1) >= 2048) { ACCKEY_error(5); return;}
+ } else if (tgeNextptrtype == ZRIGHT) {
+ jam();
+ tgeContainerptr = tgeContainerptr + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ tgeElementptr = tgeContainerptr - 1;
+ tgeKeyptr = (tgeElementptr - ZELEM_HEAD_SIZE) - fragrecptr.p->localkeylen;
+ tgeElemStep = 0 - TelemLen;
+ tgeForward = (Uint32)-1;
+ if (tgeContainerptr >= 2048) { ACCKEY_error(4); return;}
+ tgeRemLen = gePageptr.p->word32[tgeContainerptr] >> 26;
+ if ((tgeContainerptr - tgeRemLen) >= 2048) { ACCKEY_error(5); return;}
+ } else {
+ ACCKEY_error(6); return;
+ }//if
+ if (tgeRemLen >= ZCON_HEAD_SIZE + TelemLen) {
+ if (tgeRemLen > ZBUF_SIZE) {
+ ACCKEY_error(7); return;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ // There is at least one element in this container. Check if it is the element
+ // searched for.
+ /* --------------------------------------------------------------------------------- */
+ do {
+ tgeElementHeader = gePageptr.p->word32[tgeElementptr];
+ tgeRemLen = tgeRemLen - TelemLen;
+ Uint32 hashValuePart;
+ if (ElementHeader::getLocked(tgeElementHeader)) {
+ jam();
+ geTmpOperationRecPtr.i = ElementHeader::getOpPtrI(tgeElementHeader);
+ ptrCheckGuard(geTmpOperationRecPtr, coprecsize, operationrec);
+ hashValuePart = geTmpOperationRecPtr.p->hashvaluePart;
+ } else {
+ jam();
+ hashValuePart = ElementHeader::getHashValuePart(tgeElementHeader);
+ }
+ if (hashValuePart == opHashValuePart) {
+ jam();
+ Uint32 localkey1 = gePageptr.p->word32[tgeElementptr + tgeForward];
+ Uint32 localkey2 = 0;
+ bool found;
+ if (! searchLocalKey) {
+ Uint32 len = readTablePk(localkey1);
+ found = (len == operationRecPtr.p->xfrmtupkeylen) &&
+ (memcmp(Tkeydata, ckeys, len << 2) == 0);
+ } else {
+ jam();
+ found = (localkey1 == Tkeydata[0]);
+ }
+ if (found) {
+ jam();
+ tgeLocked = ElementHeader::getLocked(tgeElementHeader);
+ tgeResult = ZTRUE;
+ operationRecPtr.p->localdata[0] = localkey1;
+ operationRecPtr.p->localdata[1] = localkey2;
+ return;
+ }
+ }
+ if (tgeRemLen <= ZCON_HEAD_SIZE) {
+ break;
+ }
+ tgeElementptr = tgeElementptr + tgeElemStep;
+ } while (true);
+ }//if
+ if (tgeRemLen != ZCON_HEAD_SIZE) {
+ ACCKEY_error(8); return;
+ }//if
+ tgeContainerhead = gePageptr.p->word32[tgeContainerptr];
+ tgeNextptrtype = (tgeContainerhead >> 7) & 0x3;
+ if (tgeNextptrtype == 0) {
+ jam();
+ return; /* NO MORE CONTAINER */
+ }//if
+ tgePageindex = tgeContainerhead & 0x7f; /* NEXT CONTAINER PAGE INDEX 7 BITS */
+ if (tgePageindex > ZEMPTYLIST) {
+ ACCKEY_error(9); return;
+ }//if
+ if (((tgeContainerhead >> 9) & 1) == ZFALSE) {
+ jam();
+ tgeActivePageDir = gePageptr.p->word32[tgeContainerptr + 1]; /* NEXT PAGE ID */
+ geOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ ptrCheckGuard(geOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard((tgeActivePageDir >> 8), 256);
+ geOverflowDirptr.i = geOverflowrangeptr.p->dirArray[tgeActivePageDir >> 8];
+ ptrCheckGuard(geOverflowDirptr, cdirarraysize, directoryarray);
+ gePageptr.i = geOverflowDirptr.p->pagep[tgeActivePageDir & 0xff];
+ ptrCheckGuard(gePageptr, cpagesize, page8);
+ }//if
+ } while (1);
+ return;
+}//Dbacc::getElement()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF GET_ELEMENT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* MODULE: DELETE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* COMMITDELETE */
+/* INPUT: OPERATION_REC_PTR, PTR TO AN OPERATION RECORD. */
+/* FRAGRECPTR, PTR TO A FRAGMENT RECORD */
+/* */
+/* OUTPUT: */
+/* NONE */
+/* DESCRIPTION: DELETE OPERATIONS WILL BE COMPLETED AT THE COMMIT OF TRANSA- */
+/* CTION. THIS SUBROUTINE SEARCHS FOR ELEMENT AND DELETES IT. IT DOES SO BY */
+/* REPLACING IT WITH THE LAST ELEMENT IN THE BUCKET. IF THE DELETED ELEMENT */
+/* IS ALSO THE LAST ELEMENT THEN IT IS ONLY NECESSARY TO REMOVE THE ELEMENT. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::commitdelete(Signal* signal, bool systemRestart)
+{
+ if (!systemRestart) {
+ jam();
+ signal->theData[0] = fragrecptr.p->myfid;
+ signal->theData[1] = fragrecptr.p->myTableId;
+ signal->theData[2] = operationRecPtr.p->localdata[0];
+ Uint32 localKey = operationRecPtr.p->localdata[0];
+ Uint32 pageId = localKey >> MAX_TUPLES_BITS;
+ Uint32 pageIndex = localKey & ((1 << MAX_TUPLES_BITS) - 1);
+ signal->theData[2] = pageId;
+ signal->theData[3] = pageIndex;
+ EXECUTE_DIRECT(DBTUP, GSN_TUP_DEALLOCREQ, signal, 4);
+ jamEntry();
+ }//if
+ getdirindex(signal);
+ tlastPageindex = tgdiPageindex;
+ lastPageptr.i = gdiPageptr.i;
+ lastPageptr.p = gdiPageptr.p;
+ tlastForward = ZTRUE;
+ tlastContainerptr = (tlastPageindex << ZSHIFT_PLUS) - (tlastPageindex << ZSHIFT_MINUS);
+ tlastContainerptr = tlastContainerptr + ZHEAD_SIZE;
+ arrGuard(tlastContainerptr, 2048);
+ tlastContainerhead = lastPageptr.p->word32[tlastContainerptr];
+ tlastContainerlen = tlastContainerhead >> 26;
+ lastPrevpageptr.i = RNIL;
+ ptrNull(lastPrevpageptr);
+ tlastPrevconptr = 0;
+ getLastAndRemove(signal);
+
+ delPageptr.i = operationRecPtr.p->elementPage;
+ ptrCheckGuard(delPageptr, cpagesize, page8);
+ tdelElementptr = operationRecPtr.p->elementPointer;
+ /* --------------------------------------------------------------------------------- */
+ // Here we have to take extreme care since we do not want locks to end up after the
+ // log execution. Thus it is necessary to put back the element in unlocked shape.
+ // We thus update the element header to ensure we log an unlocked element. We do not
+ // need to restore it later since it is deleted immediately anyway.
+ /* --------------------------------------------------------------------------------- */
+ const Uint32 hv = operationRecPtr.p->hashvaluePart;
+ const Uint32 eh = ElementHeader::setUnlocked(hv, 0);
+ delPageptr.p->word32[tdelElementptr] = eh;
+ if (operationRecPtr.p->elementPage == lastPageptr.i) {
+ if (operationRecPtr.p->elementPointer == tlastElementptr) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST ELEMENT WAS THE ELEMENT TO BE DELETED. WE NEED NOT COPY IT. */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* THE DELETED ELEMENT IS NOT THE LAST. WE READ THE LAST ELEMENT AND OVERWRITE THE */
+ /* DELETED ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ tdelContainerptr = operationRecPtr.p->elementContainer;
+ tdelForward = operationRecPtr.p->elementIsforward;
+ deleteElement(signal);
+}//Dbacc::commitdelete()
+
+/* --------------------------------------------------------------------------------- */
+/* DELETE_ELEMENT */
+/* INPUT: FRAGRECPTR, POINTER TO A FRAGMENT RECORD */
+/* LAST_PAGEPTR, POINTER TO THE PAGE OF THE LAST ELEMENT */
+/* DEL_PAGEPTR, POINTER TO THE PAGE OF THE DELETED ELEMENT */
+/* TLAST_ELEMENTPTR, ELEMENT POINTER OF THE LAST ELEMENT */
+/* TDEL_ELEMENTPTR, ELEMENT POINTER OF THE DELETED ELEMENT */
+/* TLAST_FORWARD, DIRECTION OF LAST ELEMENT */
+/* TDEL_FORWARD, DIRECTION OF DELETED ELEMENT */
+/* TDEL_CONTAINERPTR, CONTAINER POINTER OF DELETED ELEMENT */
+/* DESCRIPTION: COPY LAST ELEMENT TO DELETED ELEMENT AND UPDATE UNDO LOG AND */
+/* UPDATE ANY ACTIVE OPERATION ON THE MOVED ELEMENT. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::deleteElement(Signal* signal)
+{
+ OperationrecPtr deOperationRecPtr;
+ Uint32 tdeIndex;
+ Uint32 tlastMoveElemptr;
+ Uint32 tdelMoveElemptr;
+ Uint32 guard31;
+
+ if (tlastElementptr >= 2048)
+ goto deleteElement_index_error1;
+ {
+ const Uint32 tdeElemhead = lastPageptr.p->word32[tlastElementptr];
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ datapageptr.p = delPageptr.p;
+ cundoinfolength = fragrecptr.p->elementLength;
+ if (tdelForward == ZTRUE) {
+ jam();
+ cundoElemIndex = tdelElementptr;
+ } else {
+ jam();
+ cundoElemIndex = (tdelElementptr + 1) - fragrecptr.p->elementLength;
+ }//if
+ undoWritingProcess(signal);
+ }//if
+ tlastMoveElemptr = tlastElementptr;
+ tdelMoveElemptr = tdelElementptr;
+ guard31 = fragrecptr.p->elementLength - 1;
+ for (tdeIndex = 0; tdeIndex <= guard31; tdeIndex++) {
+ dbgWord32(delPageptr, tdelMoveElemptr, lastPageptr.p->word32[tlastMoveElemptr]);
+ if ((tlastMoveElemptr >= 2048) ||
+ (tdelMoveElemptr >= 2048))
+ goto deleteElement_index_error2;
+ delPageptr.p->word32[tdelMoveElemptr] = lastPageptr.p->word32[tlastMoveElemptr];
+ tdelMoveElemptr = tdelMoveElemptr + tdelForward;
+ tlastMoveElemptr = tlastMoveElemptr + tlastForward;
+ }//for
+ if (ElementHeader::getLocked(tdeElemhead)) {
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST ELEMENT IS LOCKED AND IS THUS REFERENCED BY AN OPERATION RECORD. WE NEED */
+ /* TO UPDATE THE OPERATION RECORD WITH THE NEW REFERENCE TO THE ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ deOperationRecPtr.i = ElementHeader::getOpPtrI(tdeElemhead);
+ ptrCheckGuard(deOperationRecPtr, coprecsize, operationrec);
+ if (cundoLogActive == ZFALSE) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE DO NOT BOTHER WITH THIS INFORMATION DURING EXECUTION OF THE UNDO LOG. */
+ /* --------------------------------------------------------------------------------- */
+ deOperationRecPtr.p->elementPage = delPageptr.i;
+ deOperationRecPtr.p->elementContainer = tdelContainerptr;
+ deOperationRecPtr.p->elementPointer = tdelElementptr;
+ deOperationRecPtr.p->elementIsforward = tdelForward;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ // We need to take extreme care to not install locked records after system restart.
+ // An undo of the delete will reinstall the moved record. We have to ensure that the
+ // lock is removed to ensure that no such thing happen.
+ /* --------------------------------------------------------------------------------- */
+ Uint32 eh = ElementHeader::setUnlocked(deOperationRecPtr.p->hashvaluePart,
+ 0);
+ lastPageptr.p->word32[tlastElementptr] = eh;
+ }//if
+ return;
+ }
+
+ deleteElement_index_error1:
+ arrGuard(tlastElementptr, 2048);
+ return;
+
+ deleteElement_index_error2:
+ arrGuard(tdelMoveElemptr + guard31, 2048);
+ arrGuard(tlastMoveElemptr, 2048);
+ return;
+
+}//Dbacc::deleteElement()
+
+/* --------------------------------------------------------------------------------- */
+/* GET_LAST_AND_REMOVE */
+/* INPUT: */
+/* LAST_PAGEPTR PAGE POINTER OF FIRST CONTAINER IN SEARCH OF LAST*/
+/* TLAST_CONTAINERPTR CONTAINER INDEX OF THE SAME */
+/* TLAST_CONTAINERHEAD CONTAINER HEADER OF THE SAME */
+/* TLAST_PAGEINDEX PAGE INDEX OF THE SAME */
+/* TLAST_FORWARD CONTAINER DIRECTION OF THE SAME */
+/* TLAST_CONTAINERLEN CONTAINER LENGTH OF THE SAME */
+/* LAST_PREVPAGEPTR PAGE POINTER OF PREVIOUS CONTAINER OF THE SAME */
+/* TLAST_PREVCONPTR CONTAINER INDEX OF PREVIOUS CONTAINER OF THE SAME*/
+/* */
+/* OUTPUT: */
+/* ALL VARIABLES FROM INPUT BUT NOW CONTAINING INFO ABOUT LAST */
+/* CONTAINER. */
+/* TLAST_ELEMENTPTR LAST ELEMENT POINTER IN LAST CONTAINER */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::getLastAndRemove(Signal* signal)
+{
+ DirRangePtr glrOverflowrangeptr;
+ DirectoryarrayPtr glrOverflowDirptr;
+ Uint32 tglrHead;
+ Uint32 tglrTmp;
+
+ GLR_LOOP_10:
+ if (((tlastContainerhead >> 7) & 0x3) != 0) {
+ jam();
+ lastPrevpageptr.i = lastPageptr.i;
+ lastPrevpageptr.p = lastPageptr.p;
+ tlastPrevconptr = tlastContainerptr;
+ tlastPageindex = tlastContainerhead & 0x7f;
+ if (((tlastContainerhead >> 9) & 0x1) == ZFALSE) {
+ jam();
+ arrGuard(tlastContainerptr + 1, 2048);
+ tglrTmp = lastPageptr.p->word32[tlastContainerptr + 1];
+ glrOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ ptrCheckGuard(glrOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard((tglrTmp >> 8), 256);
+ glrOverflowDirptr.i = glrOverflowrangeptr.p->dirArray[tglrTmp >> 8];
+ ptrCheckGuard(glrOverflowDirptr, cdirarraysize, directoryarray);
+ lastPageptr.i = glrOverflowDirptr.p->pagep[tglrTmp & 0xff];
+ ptrCheckGuard(lastPageptr, cpagesize, page8);
+ }//if
+ tlastContainerptr = (tlastPageindex << ZSHIFT_PLUS) - (tlastPageindex << ZSHIFT_MINUS);
+ if (((tlastContainerhead >> 7) & 3) == ZLEFT) {
+ jam();
+ tlastForward = ZTRUE;
+ tlastContainerptr = tlastContainerptr + ZHEAD_SIZE;
+ } else if (((tlastContainerhead >> 7) & 3) == ZRIGHT) {
+ jam();
+ tlastForward = cminusOne;
+ tlastContainerptr = ((tlastContainerptr + ZHEAD_SIZE) + ZBUF_SIZE) - ZCON_HEAD_SIZE;
+ } else {
+ ndbrequire(false);
+ return;
+ }//if
+ arrGuard(tlastContainerptr, 2048);
+ tlastContainerhead = lastPageptr.p->word32[tlastContainerptr];
+ tlastContainerlen = tlastContainerhead >> 26;
+ ndbrequire(tlastContainerlen >= ((Uint32)ZCON_HEAD_SIZE + fragrecptr.p->elementLength));
+ goto GLR_LOOP_10;
+ }//if
+ tlastContainerlen = tlastContainerlen - fragrecptr.p->elementLength;
+ if (tlastForward == ZTRUE) {
+ jam();
+ tlastElementptr = tlastContainerptr + tlastContainerlen;
+ } else {
+ jam();
+ tlastElementptr = (tlastContainerptr + (ZCON_HEAD_SIZE - 1)) - tlastContainerlen;
+ }//if
+ rlPageptr.i = lastPageptr.i;
+ rlPageptr.p = lastPageptr.p;
+ trlPageindex = tlastPageindex;
+ if (((tlastContainerhead >> 10) & 1) == 1) {
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE OWNERSHIP OF BOTH PARTS OF THE CONTAINER ENDS. */
+ /* --------------------------------------------------------------------------------- */
+ if (tlastContainerlen < ZDOWN_LIMIT) {
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE DECREASED THE SIZE BELOW THE DOWN LIMIT, WE MUST GIVE UP THE OTHER */
+ /* SIDE OF THE BUFFER. */
+ /* --------------------------------------------------------------------------------- */
+ tlastContainerhead = tlastContainerhead ^ (1 << 10);
+ trlRelCon = ZFALSE;
+ if (tlastForward == ZTRUE) {
+ jam();
+ turlIndex = tlastContainerptr + (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ releaseRightlist(signal);
+ } else {
+ jam();
+ tullIndex = tlastContainerptr - (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ releaseLeftlist(signal);
+ }//if
+ }//if
+ }//if
+ if (tlastContainerlen <= 2) {
+ ndbrequire(tlastContainerlen == 2);
+ if (lastPrevpageptr.i != RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST CONTAINER IS EMPTY AND IS NOT THE FIRST CONTAINER WHICH IS NOT REMOVED. */
+ /* DELETE THE LAST CONTAINER AND UPDATE THE PREVIOUS CONTAINER. ALSO PUT THIS */
+ /* CONTAINER IN FREE CONTAINER LIST OF THE PAGE. */
+ /* --------------------------------------------------------------------------------- */
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = lastPrevpageptr.p;
+ cundoElemIndex = tlastPrevconptr;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ ndbrequire(tlastPrevconptr < 2048);
+ tglrTmp = lastPrevpageptr.p->word32[tlastPrevconptr] >> 9;
+ dbgWord32(lastPrevpageptr, tlastPrevconptr, tglrTmp << 9);
+ lastPrevpageptr.p->word32[tlastPrevconptr] = tglrTmp << 9;
+ trlRelCon = ZTRUE;
+ if (tlastForward == ZTRUE) {
+ jam();
+ tullIndex = tlastContainerptr;
+ releaseLeftlist(signal);
+ } else {
+ jam();
+ turlIndex = tlastContainerptr;
+ releaseRightlist(signal);
+ }//if
+ return;
+ }//if
+ }//if
+ tglrHead = tlastContainerhead << 6;
+ tglrHead = tglrHead >> 6;
+ tglrHead = tglrHead | (tlastContainerlen << 26);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = lastPageptr.p;
+ cundoElemIndex = tlastContainerptr;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(lastPageptr, tlastContainerptr, tglrHead);
+ arrGuard(tlastContainerptr, 2048);
+ lastPageptr.p->word32[tlastContainerptr] = tglrHead;
+}//Dbacc::getLastAndRemove()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_LEFTLIST */
+/* INPUT: */
+/* RL_PAGEPTR PAGE POINTER OF CONTAINER TO BE RELEASED */
+/* TRL_PAGEINDEX PAGE INDEX OF CONTAINER TO BE RELEASED */
+/* TURL_INDEX INDEX OF CONTAINER TO BE RELEASED */
+/* TRL_REL_CON TRUE IF CONTAINER RELEASED OTHERWISE ONLY */
+/* A PART IS RELEASED. */
+/* */
+/* OUTPUT: */
+/* NONE */
+/* */
+/* THE FREE LIST OF LEFT FREE BUFFER IN THE PAGE WILL BE UPDATE */
+/* TULL_INDEX IS INDEX TO THE FIRST WORD IN THE LEFT SIDE OF THE BUFFER */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseLeftlist(Signal* signal)
+{
+ Uint32 tullTmp;
+ Uint32 tullTmp1;
+
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = rlPageptr.p;
+ cundoElemIndex = tullIndex;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = ZPOS_EMPTY_LIST;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* IF A CONTAINER IS RELEASED AND NOT ONLY A PART THEN WE HAVE TO REMOVE IT */
+ /* FROM THE LIST OF USED CONTAINERS IN THE PAGE. THIS IN ORDER TO ENSURE THAT */
+ /* WE CAN FIND ALL LOCKED ELEMENTS DURING LOCAL CHECKPOINT. */
+ /* --------------------------------------------------------------------------------- */
+ if (trlRelCon == ZTRUE) {
+ arrGuard(tullIndex, 2048);
+ trlHead = rlPageptr.p->word32[tullIndex];
+ trlNextused = (trlHead >> 11) & 0x7f;
+ trlPrevused = (trlHead >> 18) & 0x7f;
+ if (trlNextused < ZEMPTYLIST) {
+ jam();
+ tullTmp1 = (trlNextused << ZSHIFT_PLUS) - (trlNextused << ZSHIFT_MINUS);
+ tullTmp1 = tullTmp1 + ZHEAD_SIZE;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = tullTmp1;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ tullTmp = rlPageptr.p->word32[tullTmp1] & 0xfe03ffff;
+ dbgWord32(rlPageptr, tullTmp1, tullTmp | (trlPrevused << 18));
+ rlPageptr.p->word32[tullTmp1] = tullTmp | (trlPrevused << 18);
+ } else {
+ ndbrequire(trlNextused == ZEMPTYLIST);
+ jam();
+ }//if
+ if (trlPrevused < ZEMPTYLIST) {
+ jam();
+ tullTmp1 = (trlPrevused << ZSHIFT_PLUS) - (trlPrevused << ZSHIFT_MINUS);
+ tullTmp1 = tullTmp1 + ZHEAD_SIZE;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = tullTmp1;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ tullTmp = rlPageptr.p->word32[tullTmp1] & 0xfffc07ff;
+ dbgWord32(rlPageptr, tullTmp1, tullTmp | (trlNextused << 11));
+ rlPageptr.p->word32[tullTmp1] = tullTmp | (trlNextused << 11);
+ } else {
+ ndbrequire(trlPrevused == ZEMPTYLIST);
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE FIRST IN THE LIST AND THUS WE NEED TO UPDATE THE FIRST POINTER. */
+ /* --------------------------------------------------------------------------------- */
+ tullTmp = rlPageptr.p->word32[ZPOS_EMPTY_LIST] & 0xc07fffff;
+ dbgWord32(rlPageptr, ZPOS_EMPTY_LIST, tullTmp | (trlNextused << 23));
+ rlPageptr.p->word32[ZPOS_EMPTY_LIST] = tullTmp | (trlNextused << 23);
+ }//if
+ }//if
+ dbgWord32(rlPageptr, tullIndex + 1, ZEMPTYLIST);
+ arrGuard(tullIndex + 1, 2048);
+ rlPageptr.p->word32[tullIndex + 1] = ZEMPTYLIST;
+ tullTmp1 = (rlPageptr.p->word32[ZPOS_EMPTY_LIST] >> 7) & 0x7f;
+ dbgWord32(rlPageptr, tullIndex, tullTmp1);
+ arrGuard(tullIndex, 2048);
+ rlPageptr.p->word32[tullIndex] = tullTmp1;
+ if (tullTmp1 < ZEMPTYLIST) {
+ jam();
+ tullTmp1 = (tullTmp1 << ZSHIFT_PLUS) - (tullTmp1 << ZSHIFT_MINUS);
+ tullTmp1 = (tullTmp1 + ZHEAD_SIZE) + 1;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = tullTmp1;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(rlPageptr, tullTmp1, trlPageindex);
+ rlPageptr.p->word32[tullTmp1] = trlPageindex; /* UPDATES PREV POINTER IN THE NEXT FREE */
+ } else {
+ ndbrequire(tullTmp1 == ZEMPTYLIST);
+ }//if
+ tullTmp = rlPageptr.p->word32[ZPOS_EMPTY_LIST];
+ tullTmp = (((tullTmp >> 14) << 14) | (trlPageindex << 7)) | (tullTmp & 0x7f);
+ dbgWord32(rlPageptr, ZPOS_EMPTY_LIST, tullTmp);
+ rlPageptr.p->word32[ZPOS_EMPTY_LIST] = tullTmp;
+ dbgWord32(rlPageptr, ZPOS_ALLOC_CONTAINERS, rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] - 1);
+ rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] = rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] - 1;
+ ndbrequire(rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] <= ZNIL);
+ if (((rlPageptr.p->word32[ZPOS_EMPTY_LIST] >> ZPOS_PAGE_TYPE_BIT) & 3) == 1) {
+ jam();
+ colPageptr.i = rlPageptr.i;
+ colPageptr.p = rlPageptr.p;
+ ptrCheck(colPageptr, cpagesize, page8);
+ checkoverfreelist(signal);
+ }//if
+}//Dbacc::releaseLeftlist()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_RIGHTLIST */
+/* INPUT: */
+/* RL_PAGEPTR PAGE POINTER OF CONTAINER TO BE RELEASED */
+/* TRL_PAGEINDEX PAGE INDEX OF CONTAINER TO BE RELEASED */
+/* TURL_INDEX INDEX OF CONTAINER TO BE RELEASED */
+/* TRL_REL_CON TRUE IF CONTAINER RELEASED OTHERWISE ONLY */
+/* A PART IS RELEASED. */
+/* */
+/* OUTPUT: */
+/* NONE */
+/* */
+/* THE FREE LIST OF RIGHT FREE BUFFER IN THE PAGE WILL BE UPDATE. */
+/* TURL_INDEX IS INDEX TO THE FIRST WORD IN THE RIGHT SIDE OF */
+/* THE BUFFER, WHICH IS THE LAST WORD IN THE BUFFER. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseRightlist(Signal* signal)
+{
+ Uint32 turlTmp1;
+ Uint32 turlTmp;
+
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = rlPageptr.p;
+ cundoElemIndex = turlIndex;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = ZPOS_EMPTY_LIST;
+ cundoinfolength = 2;
+ undoWritingProcess(signal);
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* IF A CONTAINER IS RELEASED AND NOT ONLY A PART THEN WE HAVE TO REMOVE IT */
+ /* FROM THE LIST OF USED CONTAINERS IN THE PAGE. THIS IN ORDER TO ENSURE THAT */
+ /* WE CAN FIND ALL LOCKED ELEMENTS DURING LOCAL CHECKPOINT. */
+ /* --------------------------------------------------------------------------------- */
+ if (trlRelCon == ZTRUE) {
+ jam();
+ arrGuard(turlIndex, 2048);
+ trlHead = rlPageptr.p->word32[turlIndex];
+ trlNextused = (trlHead >> 11) & 0x7f;
+ trlPrevused = (trlHead >> 18) & 0x7f;
+ if (trlNextused < ZEMPTYLIST) {
+ jam();
+ turlTmp1 = (trlNextused << ZSHIFT_PLUS) - (trlNextused << ZSHIFT_MINUS);
+ turlTmp1 = turlTmp1 + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = turlTmp1;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ turlTmp = rlPageptr.p->word32[turlTmp1] & 0xfe03ffff;
+ dbgWord32(rlPageptr, turlTmp1, turlTmp | (trlPrevused << 18));
+ rlPageptr.p->word32[turlTmp1] = turlTmp | (trlPrevused << 18);
+ } else {
+ ndbrequire(trlNextused == ZEMPTYLIST);
+ jam();
+ }//if
+ if (trlPrevused < ZEMPTYLIST) {
+ jam();
+ turlTmp1 = (trlPrevused << ZSHIFT_PLUS) - (trlPrevused << ZSHIFT_MINUS);
+ turlTmp1 = turlTmp1 + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = turlTmp1;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ turlTmp = rlPageptr.p->word32[turlTmp1] & 0xfffc07ff;
+ dbgWord32(rlPageptr, turlTmp1, turlTmp | (trlNextused << 11));
+ rlPageptr.p->word32[turlTmp1] = turlTmp | (trlNextused << 11);
+ } else {
+ ndbrequire(trlPrevused == ZEMPTYLIST);
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE FIRST IN THE LIST AND THUS WE NEED TO UPDATE THE FIRST POINTER */
+ /* OF THE RIGHT CONTAINER LIST. */
+ /* --------------------------------------------------------------------------------- */
+ turlTmp = rlPageptr.p->word32[ZPOS_EMPTY_LIST] & 0xff80ffff;
+ dbgWord32(rlPageptr, ZPOS_EMPTY_LIST, turlTmp | (trlNextused << 16));
+ rlPageptr.p->word32[ZPOS_EMPTY_LIST] = turlTmp | (trlNextused << 16);
+ }//if
+ }//if
+ dbgWord32(rlPageptr, turlIndex + 1, ZEMPTYLIST);
+ arrGuard(turlIndex + 1, 2048);
+ rlPageptr.p->word32[turlIndex + 1] = ZEMPTYLIST;
+ turlTmp1 = rlPageptr.p->word32[ZPOS_EMPTY_LIST] & 0x7f;
+ dbgWord32(rlPageptr, turlIndex, turlTmp1);
+ arrGuard(turlIndex, 2048);
+ rlPageptr.p->word32[turlIndex] = turlTmp1;
+ if (turlTmp1 < ZEMPTYLIST) {
+ jam();
+ turlTmp = (turlTmp1 << ZSHIFT_PLUS) - (turlTmp1 << ZSHIFT_MINUS);
+ turlTmp = turlTmp + ((ZHEAD_SIZE + ZBUF_SIZE) - (ZCON_HEAD_SIZE - 1));
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ cundoElemIndex = turlTmp;
+ cundoinfolength = 1;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(rlPageptr, turlTmp, trlPageindex);
+ rlPageptr.p->word32[turlTmp] = trlPageindex; /* UPDATES PREV POINTER IN THE NEXT FREE */
+ } else {
+ ndbrequire(turlTmp1 == ZEMPTYLIST);
+ }//if
+ turlTmp = rlPageptr.p->word32[ZPOS_EMPTY_LIST];
+ dbgWord32(rlPageptr, ZPOS_EMPTY_LIST, ((turlTmp >> 7) << 7) | trlPageindex);
+ rlPageptr.p->word32[ZPOS_EMPTY_LIST] = ((turlTmp >> 7) << 7) | trlPageindex;
+ dbgWord32(rlPageptr, ZPOS_ALLOC_CONTAINERS, rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] - 1);
+ rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] = rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] - 1;
+ ndbrequire(rlPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] <= ZNIL);
+ if (((rlPageptr.p->word32[ZPOS_EMPTY_LIST] >> ZPOS_PAGE_TYPE_BIT) & 3) == 1) {
+ jam();
+ colPageptr.i = rlPageptr.i;
+ colPageptr.p = rlPageptr.p;
+ checkoverfreelist(signal);
+ }//if
+}//Dbacc::releaseRightlist()
+
+/* --------------------------------------------------------------------------------- */
+/* CHECKOVERFREELIST */
+/* INPUT: COL_PAGEPTR, POINTER OF AN OVERFLOW PAGE RECORD. */
+/* DESCRIPTION: CHECKS IF THE PAGE HAVE TO PUT IN FREE LIST OF OVER FLOW */
+/* PAGES. WHEN IT HAVE TO, AN OVERFLOW REC PTR WILL BE ALLOCATED */
+/* TO KEEP NFORMATION ABOUT THE PAGE. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::checkoverfreelist(Signal* signal)
+{
+ Uint32 tcolTmp;
+
+ if (fragrecptr.p->loadingFlag == ZFALSE) {
+ tcolTmp = colPageptr.p->word32[ZPOS_ALLOC_CONTAINERS];
+ if (tcolTmp <= ZFREE_LIMIT) {
+ if (tcolTmp == 0) {
+ jam();
+ ropPageptr = colPageptr;
+ releaseOverpage(signal);
+ } else {
+ jam();
+ if (colPageptr.p->word32[ZPOS_OVERFLOWREC] == RNIL) {
+ ndbrequire(cfirstfreeoverrec != RNIL);
+ jam();
+ seizeOverRec(signal);
+ sorOverflowRecPtr.p->dirindex = colPageptr.p->word32[ZPOS_PAGE_ID];
+ sorOverflowRecPtr.p->overpage = colPageptr.i;
+ dbgWord32(colPageptr, ZPOS_OVERFLOWREC, sorOverflowRecPtr.i);
+ colPageptr.p->word32[ZPOS_OVERFLOWREC] = sorOverflowRecPtr.i;
+ porOverflowRecPtr = sorOverflowRecPtr;
+ putOverflowRecInFrag(signal);
+ }//if
+ }//if
+ }//if
+ }//if
+}//Dbacc::checkoverfreelist()
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* */
+/* END OF DELETE MODULE */
+/* */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* */
+/* COMMIT AND ABORT MODULE */
+/* */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+/* ABORT_OPERATION */
+/*DESCRIPTION: AN OPERATION RECORD CAN BE IN A LOCK QUEUE OF AN ELEMENT OR */
+/*OWNS THE LOCK. BY THIS SUBROUTINE THE LOCK STATE OF THE OPERATION WILL */
+/*BE CHECKED. THE OPERATION RECORD WILL BE REMOVED FROM THE QUEUE IF IT */
+/*BELONGED TO ANY ONE, OTHERWISE THE ELEMENT HEAD WILL BE UPDATED. */
+/* ------------------------------------------------------------------------- */
+void Dbacc::abortOperation(Signal* signal)
+{
+ OperationrecPtr aboOperRecPtr;
+ OperationrecPtr TaboOperRecPtr;
+ Page8Ptr aboPageidptr;
+ Uint32 taboElementptr;
+ Uint32 tmp2Olq;
+
+ if (operationRecPtr.p->lockOwner == ZTRUE) {
+ takeOutLockOwnersList(signal, operationRecPtr);
+ if (operationRecPtr.p->insertIsDone == ZTRUE) {
+ jam();
+ operationRecPtr.p->elementIsDisappeared = ZTRUE;
+ }//if
+ if ((operationRecPtr.p->nextParallelQue != RNIL) ||
+ (operationRecPtr.p->nextSerialQue != RNIL)) {
+ jam();
+ releaselock(signal);
+ } else {
+ /* --------------------------------------------------------------------------------- */
+ /* WE ARE OWNER OF THE LOCK AND NO OTHER OPERATIONS ARE QUEUED. IF INSERT OR STANDBY */
+ /* WE DELETE THE ELEMENT OTHERWISE WE REMOVE THE LOCK FROM THE ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ if (operationRecPtr.p->elementIsDisappeared == ZFALSE) {
+ jam();
+ taboElementptr = operationRecPtr.p->elementPointer;
+ aboPageidptr.i = operationRecPtr.p->elementPage;
+ tmp2Olq = ElementHeader::setUnlocked(operationRecPtr.p->hashvaluePart,
+ operationRecPtr.p->scanBits);
+ ptrCheckGuard(aboPageidptr, cpagesize, page8);
+ dbgWord32(aboPageidptr, taboElementptr, tmp2Olq);
+ arrGuard(taboElementptr, 2048);
+ aboPageidptr.p->word32[taboElementptr] = tmp2Olq;
+ return;
+ } else {
+ jam();
+ commitdelete(signal, false);
+ }//if
+ }//if
+ } else {
+ /* --------------------------------------------------------------- */
+ // We are not the lock owner.
+ /* --------------------------------------------------------------- */
+ jam();
+ takeOutFragWaitQue(signal);
+ if (operationRecPtr.p->prevParallelQue != RNIL) {
+ jam();
+ /* ---------------------------------------------------------------------------------- */
+ /* SINCE WE ARE NOT QUEUE LEADER WE NEED NOT CONSIDER IF THE ELEMENT IS TO BE DELETED.*/
+ /* We will simply remove it from the parallel list without any other rearrangements. */
+ /* ---------------------------------------------------------------------------------- */
+ aboOperRecPtr.i = operationRecPtr.p->prevParallelQue;
+ ptrCheckGuard(aboOperRecPtr, coprecsize, operationrec);
+ aboOperRecPtr.p->nextParallelQue = operationRecPtr.p->nextParallelQue;
+ if (operationRecPtr.p->nextParallelQue != RNIL) {
+ jam();
+ aboOperRecPtr.i = operationRecPtr.p->nextParallelQue;
+ ptrCheckGuard(aboOperRecPtr, coprecsize, operationrec);
+ aboOperRecPtr.p->prevParallelQue = operationRecPtr.p->prevParallelQue;
+ }//if
+ } else if (operationRecPtr.p->prevSerialQue != RNIL) {
+ /* ------------------------------------------------------------------------- */
+ // We are not in the parallel queue owning the lock. Thus we are in another parallel
+ // queue longer down in the serial queue. We are however first since prevParallelQue
+ // == RNIL.
+ /* ------------------------------------------------------------------------- */
+ if (operationRecPtr.p->nextParallelQue != RNIL) {
+ jam();
+ /* ------------------------------------------------------------------------- */
+ // We have an operation in the queue after us. We simply rearrange this parallel queue.
+ // The new leader of this parallel queue will be operation in the serial queue.
+ /* ------------------------------------------------------------------------- */
+ aboOperRecPtr.i = operationRecPtr.p->nextParallelQue;
+ ptrCheckGuard(aboOperRecPtr, coprecsize, operationrec);
+ aboOperRecPtr.p->nextSerialQue = operationRecPtr.p->nextSerialQue;
+ aboOperRecPtr.p->prevSerialQue = operationRecPtr.p->prevSerialQue;
+ aboOperRecPtr.p->prevParallelQue = RNIL; // Queue Leader
+ if (operationRecPtr.p->nextSerialQue != RNIL) {
+ jam();
+ TaboOperRecPtr.i = operationRecPtr.p->nextSerialQue;
+ ptrCheckGuard(TaboOperRecPtr, coprecsize, operationrec);
+ TaboOperRecPtr.p->prevSerialQue = aboOperRecPtr.i;
+ }//if
+ TaboOperRecPtr.i = operationRecPtr.p->prevSerialQue;
+ ptrCheckGuard(TaboOperRecPtr, coprecsize, operationrec);
+ TaboOperRecPtr.p->nextSerialQue = aboOperRecPtr.i;
+ } else {
+ jam();
+ /* ------------------------------------------------------------------------- */
+ // We are the only operation in this parallel queue. We will thus shrink the serial
+ // queue.
+ /* ------------------------------------------------------------------------- */
+ aboOperRecPtr.i = operationRecPtr.p->prevSerialQue;
+ ptrCheckGuard(aboOperRecPtr, coprecsize, operationrec);
+ aboOperRecPtr.p->nextSerialQue = operationRecPtr.p->nextSerialQue;
+ if (operationRecPtr.p->nextSerialQue != RNIL) {
+ jam();
+ aboOperRecPtr.i = operationRecPtr.p->nextSerialQue;
+ ptrCheckGuard(aboOperRecPtr, coprecsize, operationrec);
+ aboOperRecPtr.p->prevSerialQue = operationRecPtr.p->prevSerialQue;
+ }//if
+ }//if
+ }//if
+ }//if
+ /* ------------------------------------------------------------------------- */
+ // If prevParallelQue = RNIL and prevSerialQue = RNIL and we are not owner of the
+ // lock then we cannot be in any lock queue at all.
+ /* ------------------------------------------------------------------------- */
+}//Dbacc::abortOperation()
+
+void Dbacc::commitDeleteCheck()
+{
+ OperationrecPtr opPtr;
+ OperationrecPtr lastOpPtr;
+ OperationrecPtr deleteOpPtr;
+ bool elementDeleted = false;
+ bool deleteCheckOngoing = true;
+ Uint32 hashValue = 0;
+ lastOpPtr = operationRecPtr;
+ opPtr.i = operationRecPtr.p->nextParallelQue;
+ while (opPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(opPtr, coprecsize, operationrec);
+ lastOpPtr = opPtr;
+ opPtr.i = opPtr.p->nextParallelQue;
+ }//while
+ deleteOpPtr = lastOpPtr;
+ do {
+ if (deleteOpPtr.p->operation == ZDELETE) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* IF THE CURRENT OPERATION TO BE COMMITTED IS A DELETE OPERATION DUE TO A */
+ /* SCAN-TAKEOVER THE ACTUAL DELETE WILL BE PERFORMED BY THE PREVIOUS OPERATION (SCAN)*/
+ /* IN THE PARALLEL QUEUE WHICH OWNS THE LOCK.THE PROBLEM IS THAT THE SCAN OPERATION */
+ /* DOES NOT HAVE A HASH VALUE ASSIGNED TO IT SO WE COPY IT FROM THIS OPERATION. */
+ /* */
+ /* WE ASSUME THAT THIS SOLUTION WILL WORK BECAUSE THE ONLY WAY A SCAN CAN PERFORM */
+ /* A DELETE IS BY BEING FOLLOWED BY A NORMAL DELETE-OPERATION THAT HAS A HASH VALUE. */
+ /* --------------------------------------------------------------------------------- */
+ hashValue = deleteOpPtr.p->hashValue;
+ elementDeleted = true;
+ deleteCheckOngoing = false;
+ } else if ((deleteOpPtr.p->operation == ZREAD) ||
+ (deleteOpPtr.p->operation == ZSCAN_OP)) {
+ /* --------------------------------------------------------------------------------- */
+ /* We are trying to find out whether the commit will in the end delete the tuple. */
+ /* Normally the delete will be the last operation in the list of operations on this */
+ /* It is however possible to issue reads and scans in the same savepoint as the */
+ /* delete operation was issued and these can end up after the delete in the list of */
+ /* operations in the parallel queue. Thus if we discover a read or a scan we have to */
+ /* continue scanning the list looking for a delete operation. */
+ /* --------------------------------------------------------------------------------- */
+ deleteOpPtr.i = deleteOpPtr.p->prevParallelQue;
+ if (deleteOpPtr.i == RNIL) {
+ jam();
+ deleteCheckOngoing = false;
+ } else {
+ jam();
+ ptrCheckGuard(deleteOpPtr, coprecsize, operationrec);
+ }//if
+ } else {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* Finding an UPDATE or INSERT before finding a DELETE means we cannot be deleting */
+ /* as the end result of this transaction. */
+ /* --------------------------------------------------------------------------------- */
+ deleteCheckOngoing = false;
+ }//if
+ } while (deleteCheckOngoing);
+ opPtr = lastOpPtr;
+ do {
+ jam();
+ opPtr.p->commitDeleteCheckFlag = ZTRUE;
+ if (elementDeleted) {
+ jam();
+ opPtr.p->elementIsDisappeared = ZTRUE;
+ opPtr.p->hashValue = hashValue;
+ }//if
+ opPtr.i = opPtr.p->prevParallelQue;
+ if (opPtr.i == RNIL) {
+ jam();
+ break;
+ }//if
+ ptrCheckGuard(opPtr, coprecsize, operationrec);
+ } while (true);
+}//Dbacc::commitDeleteCheck()
+
+/* ------------------------------------------------------------------------- */
+/* COMMIT_OPERATION */
+/* INPUT: OPERATION_REC_PTR, POINTER TO AN OPERATION RECORD */
+/* DESCRIPTION: THE OPERATION RECORD WILL BE TAKE OUT OF ANY LOCK QUEUE. */
+/* IF IT OWNS THE ELEMENT LOCK. HEAD OF THE ELEMENT WILL BE UPDATED. */
+/* ------------------------------------------------------------------------- */
+void Dbacc::commitOperation(Signal* signal)
+{
+ OperationrecPtr tolqTmpPtr;
+ Page8Ptr coPageidptr;
+ Uint32 tcoElementptr;
+ Uint32 tmp2Olq;
+
+ if ((operationRecPtr.p->commitDeleteCheckFlag == ZFALSE) &&
+ (operationRecPtr.p->operation != ZSCAN_OP) &&
+ (operationRecPtr.p->operation != ZREAD)) {
+ jam();
+ /* This method is used to check whether the end result of the transaction
+ will be to delete the tuple. In this case all operation will be marked
+ with elementIsDisappeared = true to ensure that the last operation
+ committed will remove the tuple. We only run this once per transaction
+ (commitDeleteCheckFlag = true if performed earlier) and we don't
+ execute this code when committing a scan operation since committing
+ a scan operation only means that the scan is continuing and the scan
+ lock is released.
+ */
+ commitDeleteCheck();
+ }//if
+ if (operationRecPtr.p->lockOwner == ZTRUE) {
+ takeOutLockOwnersList(signal, operationRecPtr);
+ if ((operationRecPtr.p->nextParallelQue == RNIL) &&
+ (operationRecPtr.p->nextSerialQue == RNIL) &&
+ (operationRecPtr.p->elementIsDisappeared == ZFALSE)) {
+ /*
+ This is the normal path through the commit for operations owning the
+ lock without any queues and not a delete operation.
+ */
+ coPageidptr.i = operationRecPtr.p->elementPage;
+ tcoElementptr = operationRecPtr.p->elementPointer;
+ tmp2Olq = ElementHeader::setUnlocked(operationRecPtr.p->hashvaluePart,
+ operationRecPtr.p->scanBits);
+ ptrCheckGuard(coPageidptr, cpagesize, page8);
+ dbgWord32(coPageidptr, tcoElementptr, tmp2Olq);
+ arrGuard(tcoElementptr, 2048);
+ coPageidptr.p->word32[tcoElementptr] = tmp2Olq;
+ return;
+ } else if ((operationRecPtr.p->nextParallelQue != RNIL) ||
+ (operationRecPtr.p->nextSerialQue != RNIL)) {
+ jam();
+ /*
+ The case when there is a queue lined up.
+ Release the lock and pass it to the next operation lined up.
+ */
+ releaselock(signal);
+ return;
+ } else {
+ jam();
+ /*
+ No queue and elementIsDisappeared is true. We perform the actual delete
+ operation.
+ */
+ commitdelete(signal, false);
+ return;
+ }//if
+ } else {
+ /*
+ THE OPERATION DOES NOT OWN THE LOCK. IT MUST BE IN A LOCK QUEUE OF THE
+ ELEMENT.
+ */
+ ndbrequire(operationRecPtr.p->prevParallelQue != RNIL);
+ jam();
+ tolqTmpPtr.i = operationRecPtr.p->prevParallelQue;
+ ptrCheckGuard(tolqTmpPtr, coprecsize, operationrec);
+ tolqTmpPtr.p->nextParallelQue = operationRecPtr.p->nextParallelQue;
+ if (operationRecPtr.p->nextParallelQue != RNIL) {
+ jam();
+ tolqTmpPtr.i = operationRecPtr.p->nextParallelQue;
+ ptrCheckGuard(tolqTmpPtr, coprecsize, operationrec);
+ tolqTmpPtr.p->prevParallelQue = operationRecPtr.p->prevParallelQue;
+ }//if
+ }//if
+}//Dbacc::commitOperation()
+
+/* ------------------------------------------------------------------------- */
+/* RELEASELOCK */
+/* RESETS LOCK OF AN ELEMENT. */
+/* INFORMATION ABOUT THE ELEMENT IS SAVED IN THE OPERATION RECORD */
+/* THESE INFORMATION IS USED TO UPDATE HEADER OF THE ELEMENT */
+/* ------------------------------------------------------------------------- */
+void Dbacc::releaselock(Signal* signal)
+{
+ OperationrecPtr rloOperPtr;
+ OperationrecPtr trlOperPtr;
+ OperationrecPtr trlTmpOperPtr;
+ Uint32 TelementIsDisappeared;
+
+ trlOperPtr.i = RNIL;
+ if (operationRecPtr.p->nextParallelQue != RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* NEXT OPERATION TAKES OVER THE LOCK. We will simply move the info from the leader */
+ // to the new queue leader.
+ /* --------------------------------------------------------------------------------- */
+ trlOperPtr.i = operationRecPtr.p->nextParallelQue;
+ ptrCheckGuard(trlOperPtr, coprecsize, operationrec);
+ copyInOperPtr = trlOperPtr;
+ copyOperPtr = operationRecPtr;
+ copyOpInfo(signal);
+ trlOperPtr.p->prevParallelQue = RNIL;
+ if (operationRecPtr.p->nextSerialQue != RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THERE IS A SERIAL QUEUE. MOVE IT FROM RELEASED OP REC TO THE NEW LOCK OWNER. */
+ /* --------------------------------------------------------------------------------- */
+ trlOperPtr.p->nextSerialQue = operationRecPtr.p->nextSerialQue;
+ trlTmpOperPtr.i = trlOperPtr.p->nextSerialQue;
+ ptrCheckGuard(trlTmpOperPtr, coprecsize, operationrec);
+ trlTmpOperPtr.p->prevSerialQue = trlOperPtr.i;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* SINCE THERE ARE STILL ITEMS IN THE PARALLEL QUEUE WE NEED NOT WORRY ABOUT */
+ /* STARTING QUEUED OPERATIONS. THUS WE CAN END HERE. */
+ /* --------------------------------------------------------------------------------- */
+ } else {
+ ndbrequire(operationRecPtr.p->nextSerialQue != RNIL);
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE PARALLEL QUEUE IS EMPTY AND THE SERIAL QUEUE IS NOT EMPTY. WE NEED TO */
+ /* REARRANGE LISTS AND START A NUMBER OF OPERATIONS. */
+ /* --------------------------------------------------------------------------------- */
+ trlOperPtr.i = operationRecPtr.p->nextSerialQue;
+ ptrCheckGuard(trlOperPtr, coprecsize, operationrec);
+ copyOperPtr = operationRecPtr;
+ copyInOperPtr = trlOperPtr;
+ copyOpInfo(signal);
+ trlOperPtr.p->prevSerialQue = RNIL;
+ ndbrequire(trlOperPtr.p->prevParallelQue == RNIL);
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE MOVED TO THE NEXT PARALLEL QUEUE. WE MUST START ALL OF THOSE */
+ /* OPERATIONS WHICH UP TILL NOW HAVE BEEN QUEUED WAITING FOR THE LOCK. */
+ /* --------------------------------------------------------------------------------- */
+ rloOperPtr = operationRecPtr;
+ trlTmpOperPtr = trlOperPtr;
+ TelementIsDisappeared = trlOperPtr.p->elementIsDisappeared;
+ Uint32 ThashValue = trlOperPtr.p->hashValue;
+ do {
+ /* --------------------------------------------------------------------------------- */
+ // Ensure that all operations in the queue are assigned with the elementIsDisappeared
+ // to ensure that the element is removed after a previous delete. An insert does
+ // however revert this decision since the element is put back again. Local checkpoints
+ // complicate life here since they do not execute the next operation but simply change
+ // the state on the operation. We need to set-up the variable elementIsDisappeared
+ // properly even when local checkpoints and inserts/writes after deletes occur.
+ /* --------------------------------------------------------------------------------- */
+ trlTmpOperPtr.p->elementIsDisappeared = TelementIsDisappeared;
+ if (TelementIsDisappeared == ZTRUE) {
+ /* --------------------------------------------------------------------------------- */
+ // If the elementIsDisappeared is set then we know that the hashValue is also set
+ // since it always originates from a committing abort or a aborting insert. Scans
+ // do not initialise the hashValue and must have this value initialised if they are
+ // to successfully commit the delete.
+ /* --------------------------------------------------------------------------------- */
+ jam();
+ trlTmpOperPtr.p->hashValue = ThashValue;
+ }//if
+ trlTmpOperPtr.p->localdata[0] = trlOperPtr.p->localdata[0];
+ trlTmpOperPtr.p->localdata[1] = trlOperPtr.p->localdata[1];
+ /* --------------------------------------------------------------------------------- */
+ // Restart the queued operation.
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr = trlTmpOperPtr;
+ TelementIsDisappeared = executeNextOperation(signal);
+ ThashValue = operationRecPtr.p->hashValue;
+ if (trlTmpOperPtr.p->nextParallelQue != RNIL) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // We will continue with the next operation in the parallel queue and start this as
+ // well.
+ /* --------------------------------------------------------------------------------- */
+ trlTmpOperPtr.i = trlTmpOperPtr.p->nextParallelQue;
+ ptrCheckGuard(trlTmpOperPtr, coprecsize, operationrec);
+ } else {
+ jam();
+ break;
+ }//if
+ } while (1);
+ operationRecPtr = rloOperPtr;
+ }//if
+
+ // Insert the next op into the lock owner list
+ insertLockOwnersList(signal, trlOperPtr);
+ return;
+}//Dbacc::releaselock()
+
+/* --------------------------------------------------------------------------------- */
+/* COPY_OP_INFO */
+/* INPUT: COPY_IN_OPER_PTR AND COPY_OPER_PTR. */
+/* DESCRIPTION:INFORMATION ABOUT THE ELEMENT WILL BE MOVED FROM OPERATION */
+/* REC TO QUEUE OP REC. QUE OP REC TAKES OVER THE LOCK. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::copyOpInfo(Signal* signal)
+{
+ Page8Ptr coiPageidptr;
+
+ copyInOperPtr.p->elementPage = copyOperPtr.p->elementPage;
+ copyInOperPtr.p->elementIsforward = copyOperPtr.p->elementIsforward;
+ copyInOperPtr.p->elementContainer = copyOperPtr.p->elementContainer;
+ copyInOperPtr.p->elementPointer = copyOperPtr.p->elementPointer;
+ copyInOperPtr.p->scanBits = copyOperPtr.p->scanBits;
+ copyInOperPtr.p->hashvaluePart = copyOperPtr.p->hashvaluePart;
+ copyInOperPtr.p->elementIsDisappeared = copyOperPtr.p->elementIsDisappeared;
+ if (copyInOperPtr.p->elementIsDisappeared == ZTRUE) {
+ /* --------------------------------------------------------------------------------- */
+ // If the elementIsDisappeared is set then we know that the hashValue is also set
+ // since it always originates from a committing abort or a aborting insert. Scans
+ // do not initialise the hashValue and must have this value initialised if they are
+ // to successfully commit the delete.
+ /* --------------------------------------------------------------------------------- */
+ jam();
+ copyInOperPtr.p->hashValue = copyOperPtr.p->hashValue;
+ }//if
+ coiPageidptr.i = copyOperPtr.p->elementPage;
+ ptrCheckGuard(coiPageidptr, cpagesize, page8);
+ const Uint32 tmp = ElementHeader::setLocked(copyInOperPtr.i);
+ dbgWord32(coiPageidptr, copyOperPtr.p->elementPointer, tmp);
+ arrGuard(copyOperPtr.p->elementPointer, 2048);
+ coiPageidptr.p->word32[copyOperPtr.p->elementPointer] = tmp;
+ copyInOperPtr.p->localdata[0] = copyOperPtr.p->localdata[0];
+ copyInOperPtr.p->localdata[1] = copyOperPtr.p->localdata[1];
+}//Dbacc::copyOpInfo()
+
+/* ******************--------------------------------------------------------------- */
+/* EXECUTE NEXT OPERATION */
+/* NEXT OPERATION IN A LOCK QUEUE WILL BE EXECUTED. */
+/* --------------------------------------------------------------------------------- */
+Uint32 Dbacc::executeNextOperation(Signal* signal)
+{
+ ndbrequire(operationRecPtr.p->transactionstate == ACTIVE);
+ if (fragrecptr.p->stopQueOp == ZTRUE) {
+ Uint32 TelemDisappeared;
+ jam();
+ TelemDisappeared = operationRecPtr.p->elementIsDisappeared;
+ if ((operationRecPtr.p->elementIsDisappeared == ZTRUE) &&
+ (operationRecPtr.p->prevParallelQue == RNIL) &&
+ ((operationRecPtr.p->operation == ZINSERT) ||
+ (operationRecPtr.p->operation == ZWRITE))) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // In this case we do not wish to change the elementIsDisappeared since that would
+ // create an error the next time this method is called for this operation after local
+ // checkpoint starts up operations again. We must however ensure that operations
+ // that follow in the queue do not get the value ZTRUE when actually an INSERT/WRITE
+ // precedes them (only if the INSERT/WRITE is the first operation).
+ /* --------------------------------------------------------------------------------- */
+ TelemDisappeared = ZFALSE;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* A LOCAL CHECKPOINT HAS STOPPED OPERATIONS. WE MUST NOT START THE OPERATION */
+ /* AT THIS TIME. WE SET THE STATE TO INDICATE THAT WE ARE READY TO START AS */
+ /* SOON AS WE ARE ALLOWED. */
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr.p->opState = WAIT_EXE_OP;
+ return TelemDisappeared;
+ }//if
+ takeOutFragWaitQue(signal);
+ if (operationRecPtr.p->elementIsDisappeared == ZTRUE) {
+ /* --------------------------------------------------------------------------------- */
+ /* PREVIOUS OPERATION WAS DELETE OPERATION AND THE ELEMENT IS ALREADY DELETED. */
+ /* --------------------------------------------------------------------------------- */
+ if (((operationRecPtr.p->operation != ZINSERT) &&
+ (operationRecPtr.p->operation != ZWRITE)) ||
+ (operationRecPtr.p->prevParallelQue != RNIL)) {
+ if (operationRecPtr.p->operation != ZSCAN_OP ||
+ operationRecPtr.p->isAccLockReq) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // Updates and reads with a previous delete simply aborts with read error indicating
+ // that tuple did not exist. Also inserts and writes not being the first operation.
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr.p->transactionstate = WAIT_COMMIT_ABORT;
+ signal->theData[0] = operationRecPtr.p->userptr;
+ signal->theData[1] = ZREAD_ERROR;
+ sendSignal(operationRecPtr.p->userblockref, GSN_ACCKEYREF, signal, 2, JBB);
+ return operationRecPtr.p->elementIsDisappeared;
+ } else {
+ /* --------------------------------------------------------------------------------- */
+ /* ABORT OF OPERATION NEEDED BUT THE OPERATION IS A SCAN => SPECIAL TREATMENT. */
+ /* IF THE SCAN WAITS IN QUEUE THEN WE MUST REMOVE THE OPERATION FROM THE SCAN */
+ /* LOCK QUEUE AND IF NO MORE OPERATIONS ARE QUEUED THEN WE SHOULD RESTART THE */
+ /* SCAN PROCESS. OTHERWISE WE SIMPLY RELEASE THE OPERATION AND DECREASE THE */
+ /* NUMBER OF LOCKS HELD. */
+ /* --------------------------------------------------------------------------------- */
+ takeOutScanLockQueue(operationRecPtr.p->scanRecPtr);
+ putReadyScanQueue(signal, operationRecPtr.p->scanRecPtr);
+ return operationRecPtr.p->elementIsDisappeared;
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ // Insert and writes can continue but need to be converted to inserts.
+ /* --------------------------------------------------------------------------------- */
+ jam();
+ operationRecPtr.p->elementIsDisappeared = ZFALSE;
+ operationRecPtr.p->operation = ZINSERT;
+ operationRecPtr.p->insertIsDone = ZTRUE;
+ } else if (operationRecPtr.p->operation == ZINSERT) {
+ bool abortFlag = true;
+ if (operationRecPtr.p->prevParallelQue != RNIL) {
+ OperationrecPtr prevOpPtr;
+ jam();
+ prevOpPtr.i = operationRecPtr.p->prevParallelQue;
+ ptrCheckGuard(prevOpPtr, coprecsize, operationrec);
+ if (prevOpPtr.p->operation == ZDELETE) {
+ jam();
+ abortFlag = false;
+ }//if
+ }//if
+ if (abortFlag) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* ELEMENT STILL REMAINS AND WE ARE TRYING TO INSERT IT AGAIN. THIS IS CLEARLY */
+ /* NOT A GOOD IDEA. */
+ /* --------------------------------------------------------------------------------- */
+ operationRecPtr.p->transactionstate = WAIT_COMMIT_ABORT;
+ signal->theData[0] = operationRecPtr.p->userptr;
+ signal->theData[1] = ZWRITE_ERROR;
+ sendSignal(operationRecPtr.p->userblockref, GSN_ACCKEYREF, signal, 2, JBB);
+ return operationRecPtr.p->elementIsDisappeared;
+ }//if
+ }//if
+ if (operationRecPtr.p->operation == ZSCAN_OP &&
+ ! operationRecPtr.p->isAccLockReq) {
+ jam();
+ takeOutScanLockQueue(operationRecPtr.p->scanRecPtr);
+ putReadyScanQueue(signal, operationRecPtr.p->scanRecPtr);
+ } else {
+ jam();
+ sendAcckeyconf(signal);
+ sendSignal(operationRecPtr.p->userblockref, GSN_ACCKEYCONF, signal, 6, JBB);
+ }//if
+ return operationRecPtr.p->elementIsDisappeared;
+}//Dbacc::executeNextOperation()
+
+/* --------------------------------------------------------------------------------- */
+/* TAKE_OUT_FRAG_WAIT_QUE */
+/* DESCRIPTION: AN OPERATION WHICH OWNS A LOCK OF AN ELEMENT, IS IN A LIST */
+/* OF THE FRAGMENT. THIS LIST IS USED TO STOP THE QUEUE OPERATION */
+/* DURING CREATE CHECK POINT PROSESS FOR STOP AND RESTART OF THE */
+/* OPERATIONS. THIS SUBRUTIN TAKES A OPERATION RECORD OUT OF THE LIST */
+/* -------------------------------------------------------------------------------- */
+void Dbacc::takeOutFragWaitQue(Signal* signal)
+{
+ OperationrecPtr tofwqOperRecPtr;
+
+ if (operationRecPtr.p->opState == WAIT_IN_QUEUE) {
+ if (fragrecptr.p->sentWaitInQueOp == operationRecPtr.i) {
+ jam();
+ fragrecptr.p->sentWaitInQueOp = operationRecPtr.p->nextQueOp;
+ }//if
+ if (operationRecPtr.p->prevQueOp != RNIL) {
+ jam();
+ tofwqOperRecPtr.i = operationRecPtr.p->prevQueOp;
+ ptrCheckGuard(tofwqOperRecPtr, coprecsize, operationrec);
+ tofwqOperRecPtr.p->nextQueOp = operationRecPtr.p->nextQueOp;
+ } else {
+ jam();
+ fragrecptr.p->firstWaitInQueOp = operationRecPtr.p->nextQueOp;
+ }//if
+ if (operationRecPtr.p->nextQueOp != RNIL) {
+ jam();
+ tofwqOperRecPtr.i = operationRecPtr.p->nextQueOp;
+ ptrCheckGuard(tofwqOperRecPtr, coprecsize, operationrec);
+ tofwqOperRecPtr.p->prevQueOp = operationRecPtr.p->prevQueOp;
+ } else {
+ jam();
+ fragrecptr.p->lastWaitInQueOp = operationRecPtr.p->prevQueOp;
+ }//if
+ operationRecPtr.p->opState = FREE_OP;
+ return;
+ } else {
+ ndbrequire(operationRecPtr.p->opState == FREE_OP);
+ }//if
+}//Dbacc::takeOutFragWaitQue()
+
+/**
+ * takeOutLockOwnersList
+ *
+ * Description: Take out an operation from the doubly linked
+ * lock owners list on the fragment.
+ *
+ */
+void Dbacc::takeOutLockOwnersList(Signal* signal,
+ const OperationrecPtr& outOperPtr)
+{
+ const Uint32 Tprev = outOperPtr.p->prevLockOwnerOp;
+ const Uint32 Tnext = outOperPtr.p->nextLockOwnerOp;
+
+#ifdef VM_TRACE
+ // Check that operation is already in the list
+ OperationrecPtr tmpOperPtr;
+ bool inList = false;
+ tmpOperPtr.i = fragrecptr.p->lockOwnersList;
+ while (tmpOperPtr.i != RNIL){
+ ptrCheckGuard(tmpOperPtr, coprecsize, operationrec);
+ if (tmpOperPtr.i == outOperPtr.i)
+ inList = true;
+ tmpOperPtr.i = tmpOperPtr.p->nextLockOwnerOp;
+ }
+ ndbrequire(inList == true);
+#endif
+
+ ndbrequire(outOperPtr.p->lockOwner == ZTRUE);
+ outOperPtr.p->lockOwner = ZFALSE;
+
+ // Fast path through the code for the common case.
+ if ((Tprev == RNIL) && (Tnext == RNIL)) {
+ ndbrequire(fragrecptr.p->lockOwnersList == outOperPtr.i);
+ fragrecptr.p->lockOwnersList = RNIL;
+ return;
+ }
+
+ // Check previous operation
+ if (Tprev != RNIL) {
+ jam();
+ arrGuard(Tprev, coprecsize);
+ operationrec[Tprev].nextLockOwnerOp = Tnext;
+ } else {
+ fragrecptr.p->lockOwnersList = Tnext;
+ }//if
+
+ // Check next operation
+ if (Tnext == RNIL) {
+ return;
+ } else {
+ jam();
+ arrGuard(Tnext, coprecsize);
+ operationrec[Tnext].prevLockOwnerOp = Tprev;
+ }//if
+
+ return;
+}//Dbacc::takeOutLockOwnersList()
+
+/**
+ * insertLockOwnersList
+ *
+ * Description: Insert an operation first in the dubly linked lock owners
+ * list on the fragment.
+ *
+ */
+void Dbacc::insertLockOwnersList(Signal* signal,
+ const OperationrecPtr& insOperPtr)
+{
+ OperationrecPtr tmpOperPtr;
+
+#ifdef VM_TRACE
+ // Check that operation is not already in list
+ tmpOperPtr.i = fragrecptr.p->lockOwnersList;
+ while(tmpOperPtr.i != RNIL){
+ ptrCheckGuard(tmpOperPtr, coprecsize, operationrec);
+ ndbrequire(tmpOperPtr.i != insOperPtr.i);
+ tmpOperPtr.i = tmpOperPtr.p->nextLockOwnerOp;
+ }
+#endif
+
+ ndbrequire(insOperPtr.p->lockOwner == ZFALSE);
+
+ insOperPtr.p->lockOwner = ZTRUE;
+ insOperPtr.p->prevLockOwnerOp = RNIL;
+ tmpOperPtr.i = fragrecptr.p->lockOwnersList;
+ fragrecptr.p->lockOwnersList = insOperPtr.i;
+ insOperPtr.p->nextLockOwnerOp = tmpOperPtr.i;
+ if (tmpOperPtr.i == RNIL) {
+ return;
+ } else {
+ jam();
+ ptrCheckGuard(tmpOperPtr, coprecsize, operationrec);
+ tmpOperPtr.p->prevLockOwnerOp = insOperPtr.i;
+ }//if
+}//Dbacc::insertLockOwnersList()
+
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF COMMIT AND ABORT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ALLOC_OVERFLOW_PAGE */
+/* DESCRIPTION: */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::allocOverflowPage(Signal* signal)
+{
+ DirRangePtr aopDirRangePtr;
+ DirectoryarrayPtr aopOverflowDirptr;
+ OverflowRecordPtr aopOverflowRecPtr;
+ Uint32 taopTmp1;
+ Uint32 taopTmp2;
+ Uint32 taopTmp3;
+
+ tresult = 0;
+ if ((cfirstfreepage == RNIL) &&
+ (cfreepage >= cpagesize)) {
+ jam();
+ zpagesize_error("Dbacc::allocOverflowPage");
+ tresult = ZPAGESIZE_ERROR;
+ return;
+ }//if
+ if (fragrecptr.p->firstFreeDirindexRec != RNIL) {
+ jam();
+ /* FRAGRECPTR:FIRST_FREE_DIRINDEX_REC POINTS */
+ /* TO THE FIRST ELEMENT IN A FREE LIST OF THE */
+ /* DIRECTORY INDEX WICH HAVE NULL AS PAGE */
+ aopOverflowRecPtr.i = fragrecptr.p->firstFreeDirindexRec;
+ ptrCheckGuard(aopOverflowRecPtr, coverflowrecsize, overflowRecord);
+ troOverflowRecPtr.p = aopOverflowRecPtr.p;
+ takeRecOutOfFreeOverdir(signal);
+ } else if (cfirstfreeoverrec == RNIL) {
+ jam();
+ tresult = ZOVER_REC_ERROR;
+ return;
+ } else if ((cfirstfreedir == RNIL) &&
+ (cdirarraysize <= cdirmemory)) {
+ jam();
+ tresult = ZDIRSIZE_ERROR;
+ return;
+ } else {
+ jam();
+ seizeOverRec(signal);
+ aopOverflowRecPtr = sorOverflowRecPtr;
+ aopOverflowRecPtr.p->dirindex = fragrecptr.p->lastOverIndex;
+ }//if
+ aopOverflowRecPtr.p->nextOverRec = RNIL;
+ aopOverflowRecPtr.p->prevOverRec = RNIL;
+ fragrecptr.p->firstOverflowRec = aopOverflowRecPtr.i;
+ fragrecptr.p->lastOverflowRec = aopOverflowRecPtr.i;
+ taopTmp1 = aopOverflowRecPtr.p->dirindex;
+ aopDirRangePtr.i = fragrecptr.p->overflowdir;
+ taopTmp2 = taopTmp1 >> 8;
+ taopTmp3 = taopTmp1 & 0xff;
+ ptrCheckGuard(aopDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(taopTmp2, 256);
+ if (aopDirRangePtr.p->dirArray[taopTmp2] == RNIL) {
+ jam();
+ seizeDirectory(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ aopDirRangePtr.p->dirArray[taopTmp2] = sdDirptr.i;
+ }//if
+ aopOverflowDirptr.i = aopDirRangePtr.p->dirArray[taopTmp2];
+ seizePage(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ ptrCheckGuard(aopOverflowDirptr, cdirarraysize, directoryarray);
+ aopOverflowDirptr.p->pagep[taopTmp3] = spPageptr.i;
+ tiopPageId = aopOverflowRecPtr.p->dirindex;
+ iopOverflowRecPtr = aopOverflowRecPtr;
+ iopPageptr = spPageptr;
+ initOverpage(signal);
+ aopOverflowRecPtr.p->overpage = spPageptr.i;
+ if (fragrecptr.p->lastOverIndex <= aopOverflowRecPtr.p->dirindex) {
+ jam();
+ ndbrequire(fragrecptr.p->lastOverIndex == aopOverflowRecPtr.p->dirindex);
+ fragrecptr.p->lastOverIndex++;
+ }//if
+}//Dbacc::allocOverflowPage()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* EXPAND/SHRINK MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/*EXPANDCHECK EXPAND BUCKET ORD */
+/* SENDER: ACC, LEVEL B */
+/* INPUT: FRAGRECPTR, POINTS TO A FRAGMENT RECORD. */
+/* DESCRIPTION: A BUCKET OF A FRAGMENT PAGE WILL BE EXPAND INTO TWO BUCKETS */
+/* ACCORDING TO LH3. */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* EXPANDCHECK EXPAND BUCKET ORD */
+/* ******************------------------------------+ */
+/* SENDER: ACC, LEVEL B */
+/* A BUCKET OF THE FRAGMENT WILL */
+/* BE EXPANDED ACORDING TO LH3, */
+/* AND COMMIT TRANSACTION PROCESS */
+/* WILL BE CONTINUED */
+Uint32 Dbacc::checkScanExpand(Signal* signal)
+{
+ Uint32 Ti;
+ Uint32 TreturnCode = 0;
+ Uint32 TPageIndex;
+ Uint32 TDirInd;
+ Uint32 TSplit;
+ Uint32 TreleaseInd = 0;
+ Uint32 TreleaseScanBucket;
+ Uint32 TreleaseScanIndicator[4];
+ DirectoryarrayPtr TDirptr;
+ DirRangePtr TDirRangePtr;
+ Page8Ptr TPageptr;
+ ScanRecPtr TscanPtr;
+ RootfragmentrecPtr Trootfragrecptr;
+
+ Trootfragrecptr.i = fragrecptr.p->myroot;
+ TSplit = fragrecptr.p->p;
+ ptrCheckGuard(Trootfragrecptr, crootfragmentsize, rootfragmentrec);
+ for (Ti = 0; Ti < 4; Ti++) {
+ TreleaseScanIndicator[Ti] = 0;
+ if (Trootfragrecptr.p->scan[Ti] != RNIL) {
+ //-------------------------------------------------------------
+ // A scan is ongoing on this particular local fragment. We have
+ // to check its current state.
+ //-------------------------------------------------------------
+ TscanPtr.i = Trootfragrecptr.p->scan[Ti];
+ ptrCheckGuard(TscanPtr, cscanRecSize, scanRec);
+ if (TscanPtr.p->activeLocalFrag == fragrecptr.i) {
+ if (TscanPtr.p->scanBucketState == ScanRec::FIRST_LAP) {
+ if (TSplit == TscanPtr.p->nextBucketIndex) {
+ jam();
+ //-------------------------------------------------------------
+ // We are currently scanning this bucket. We cannot split it
+ // simultaneously with the scan. We have to pass this offer for
+ // splitting the bucket.
+ //-------------------------------------------------------------
+ TreturnCode = 1;
+ return TreturnCode;
+ } else if (TSplit > TscanPtr.p->nextBucketIndex) {
+ jam();
+ //-------------------------------------------------------------
+ // This bucket has not yet been scanned. We must reset the scanned
+ // bit indicator for this scan on this bucket.
+ //-------------------------------------------------------------
+ TreleaseScanIndicator[Ti] = 1;
+ TreleaseInd = 1;
+ } else {
+ jam();
+ }//if
+ } else if (TscanPtr.p->scanBucketState == ScanRec::SECOND_LAP) {
+ jam();
+ //-------------------------------------------------------------
+ // We are performing a second lap to handle buckets that was
+ // merged during the first lap of scanning. During this second
+ // lap we do not allow any splits or merges.
+ //-------------------------------------------------------------
+ TreturnCode = 1;
+ return TreturnCode;
+ } else {
+ ndbrequire(TscanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED);
+ jam();
+ //-------------------------------------------------------------
+ // The scan is completed and we can thus go ahead and perform
+ // the split.
+ //-------------------------------------------------------------
+ }//if
+ }//if
+ }//if
+ }//for
+ if (TreleaseInd == 1) {
+ TreleaseScanBucket = TSplit;
+ TDirRangePtr.i = fragrecptr.p->directory;
+ TPageIndex = TreleaseScanBucket & ((1 << fragrecptr.p->k) - 1); /* PAGE INDEX OBS K = 6 */
+ TDirInd = TreleaseScanBucket >> fragrecptr.p->k; /* DIRECTORY INDEX OBS K = 6 */
+ ptrCheckGuard(TDirRangePtr, cdirrangesize, dirRange);
+ arrGuard((TDirInd >> 8), 256);
+ TDirptr.i = TDirRangePtr.p->dirArray[TDirInd >> 8];
+ ptrCheckGuard(TDirptr, cdirarraysize, directoryarray);
+ TPageptr.i = TDirptr.p->pagep[TDirInd & 0xff];
+ ptrCheckGuard(TPageptr, cpagesize, page8);
+ for (Ti = 0; Ti < 4; Ti++) {
+ if (TreleaseScanIndicator[Ti] == 1) {
+ jam();
+ scanPtr.i = Trootfragrecptr.p->scan[Ti];
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+ rsbPageidptr = TPageptr;
+ trsbPageindex = TPageIndex;
+ releaseScanBucket(signal);
+ }//if
+ }//for
+ }//if
+ return TreturnCode;
+}//Dbacc::checkScanExpand()
+
+void Dbacc::execEXPANDCHECK2(Signal* signal)
+{
+ jamEntry();
+
+ if(refToBlock(signal->getSendersBlockRef()) == DBLQH){
+ jam();
+ reenable_expand_after_redo_log_exection_complete(signal);
+ return;
+ }
+
+ DirectoryarrayPtr newDirptr;
+
+ fragrecptr.i = signal->theData[0];
+ tresult = 0; /* 0= FALSE,1= TRUE,> ZLIMIT_OF_ERROR =ERRORCODE */
+ Uint32 tmp = 1;
+ tmp = tmp << 31;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->expandFlag = 0;
+ if (fragrecptr.p->slack < tmp) {
+ jam();
+ /* IT MEANS THAT IF SLACK > ZERO */
+ /*--------------------------------------------------------------*/
+ /* THE SLACK HAS IMPROVED AND IS NOW ACCEPTABLE AND WE */
+ /* CAN FORGET ABOUT THE EXPAND PROCESS. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ if (fragrecptr.p->firstOverflowRec == RNIL) {
+ jam();
+ allocOverflowPage(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* WE COULD NOT ALLOCATE ANY OVERFLOW PAGE. THUS WE HAVE TO STOP*/
+ /* THE EXPAND SINCE WE CANNOT GUARANTEE ITS COMPLETION. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+ if (cfirstfreepage == RNIL) {
+ if (cfreepage >= cpagesize) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* WE HAVE TO STOP THE EXPAND PROCESS SINCE THERE ARE NO FREE */
+ /* PAGES. THIS MEANS THAT WE COULD BE FORCED TO CRASH SINCE WE */
+ /* CANNOT COMPLETE THE EXPAND. TO AVOID THE CRASH WE EXIT HERE. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+ if (checkScanExpand(signal) == 1) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // A scan state was inconsistent with performing an expand
+ // operation.
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_EXPAND) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // We did not have enough undo log buffers to start up an
+ // expand operation
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+
+ /*--------------------------------------------------------------------------*/
+ /* WE START BY FINDING THE PAGE, THE PAGE INDEX AND THE PAGE DIRECTORY*/
+ /* OF THE NEW BUCKET WHICH SHALL RECEIVE THE ELEMENT WHICH HAVE A 1 IN*/
+ /* THE NEXT HASH BIT. THIS BIT IS USED IN THE SPLIT MECHANISM TO */
+ /* DECIDE WHICH ELEMENT GOES WHERE. */
+ /*--------------------------------------------------------------------------*/
+ expDirRangePtr.i = fragrecptr.p->directory;
+ texpReceivedBucket = (fragrecptr.p->maxp + fragrecptr.p->p) + 1; /* RECEIVED BUCKET */
+ texpDirInd = texpReceivedBucket >> fragrecptr.p->k;
+ newDirptr.i = RNIL;
+ ptrNull(newDirptr);
+ texpDirRangeIndex = texpDirInd >> 8;
+ ptrCheckGuard(expDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(texpDirRangeIndex, 256);
+ expDirptr.i = expDirRangePtr.p->dirArray[texpDirRangeIndex];
+ if (expDirptr.i == RNIL) {
+ jam();
+ seizeDirectory(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ return;
+ } else {
+ jam();
+ newDirptr = sdDirptr;
+ expDirptr = sdDirptr;
+ expDirRangePtr.p->dirArray[texpDirRangeIndex] = sdDirptr.i;
+ }//if
+ } else {
+ ptrCheckGuard(expDirptr, cdirarraysize, directoryarray);
+ }//if
+ texpDirPageIndex = texpDirInd & 0xff;
+ expPageptr.i = expDirptr.p->pagep[texpDirPageIndex];
+ if (expPageptr.i == RNIL) {
+ jam();
+ seizePage(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ if (newDirptr.i != RNIL) {
+ jam();
+ rdDirptr.i = newDirptr.i;
+ releaseDirectory(signal);
+ }//if
+ return;
+ }//if
+ expDirptr.p->pagep[texpDirPageIndex] = spPageptr.i;
+ tipPageId = texpDirInd;
+ inpPageptr = spPageptr;
+ initPage(signal);
+ fragrecptr.p->dirsize++;
+ expPageptr = spPageptr;
+ } else {
+ ptrCheckGuard(expPageptr, cpagesize, page8);
+ }//if
+
+ fragrecptr.p->expReceivePageptr = expPageptr.i;
+ fragrecptr.p->expReceiveIndex = texpReceivedBucket & ((1 << fragrecptr.p->k) - 1);
+ /*--------------------------------------------------------------------------*/
+ /* THE NEXT ACTION IS TO FIND THE PAGE, THE PAGE INDEX AND THE PAGE */
+ /* DIRECTORY OF THE BUCKET TO BE SPLIT. */
+ /*--------------------------------------------------------------------------*/
+ expDirRangePtr.i = fragrecptr.p->directory;
+ cexcPageindex = fragrecptr.p->p & ((1 << fragrecptr.p->k) - 1); /* PAGE INDEX OBS K = 6 */
+ texpDirInd = fragrecptr.p->p >> fragrecptr.p->k; /* DIRECTORY INDEX OBS K = 6 */
+ ptrCheckGuard(expDirRangePtr, cdirrangesize, dirRange);
+ arrGuard((texpDirInd >> 8), 256);
+ expDirptr.i = expDirRangePtr.p->dirArray[texpDirInd >> 8];
+ ptrCheckGuard(expDirptr, cdirarraysize, directoryarray);
+ excPageptr.i = expDirptr.p->pagep[texpDirInd & 0xff];
+ fragrecptr.p->expSenderIndex = cexcPageindex;
+ fragrecptr.p->expSenderPageptr = excPageptr.i;
+ if (excPageptr.i == RNIL) {
+ jam();
+ endofexpLab(signal); /* EMPTY BUCKET */
+ return;
+ }//if
+ fragrecptr.p->expReceiveForward = ZTRUE;
+ ptrCheckGuard(excPageptr, cpagesize, page8);
+ expandcontainer(signal);
+ endofexpLab(signal);
+ return;
+}//Dbacc::execEXPANDCHECK2()
+
+void Dbacc::endofexpLab(Signal* signal)
+{
+ fragrecptr.p->p++;
+ fragrecptr.p->slack += fragrecptr.p->maxloadfactor;
+ fragrecptr.p->expandCounter++;
+ if (fragrecptr.p->p > fragrecptr.p->maxp) {
+ jam();
+ fragrecptr.p->maxp = (fragrecptr.p->maxp << 1) | 1;
+ fragrecptr.p->lhdirbits++;
+ fragrecptr.p->hashcheckbit++;
+ fragrecptr.p->p = 0;
+ }//if
+ Uint32 noOfBuckets = (fragrecptr.p->maxp + 1) + fragrecptr.p->p;
+ Uint32 Thysteres = fragrecptr.p->maxloadfactor - fragrecptr.p->minloadfactor;
+ fragrecptr.p->slackCheck = noOfBuckets * Thysteres;
+ if (fragrecptr.p->slack > (1u << 31)) {
+ jam();
+ /* IT MEANS THAT IF SLACK < ZERO */
+ /* --------------------------------------------------------------------------------- */
+ /* IT IS STILL NECESSARY TO EXPAND THE FRAGMENT EVEN MORE. START IT FROM HERE */
+ /* WITHOUT WAITING FOR NEXT COMMIT ON THE FRAGMENT. */
+ /* --------------------------------------------------------------------------------- */
+ fragrecptr.p->expandFlag = 2;
+ signal->theData[0] = fragrecptr.i;
+ signal->theData[1] = fragrecptr.p->p;
+ signal->theData[2] = fragrecptr.p->maxp;
+ sendSignal(cownBlockref, GSN_EXPANDCHECK2, signal, 3, JBB);
+ }//if
+ return;
+}//Dbacc::endofexpLab()
+
+void Dbacc::reenable_expand_after_redo_log_exection_complete(Signal* signal){
+
+ tabptr.i = signal->theData[0];
+ Uint32 fragId = signal->theData[1];
+
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ ndbrequire(getrootfragmentrec(signal, rootfragrecptr, fragId));
+#if 0
+ ndbout_c("reenable expand check for table %d fragment: %d",
+ tabptr.i, fragId);
+#endif
+
+ for (Uint32 i = 0; i < 2; i++) {
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[i];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ switch(fragrecptr.p->expandFlag){
+ case 0:
+ /**
+ * Hmm... this means that it's alreay has been reenabled...
+ */
+ ndbassert(false);
+ continue;
+ case 1:
+ /**
+ * Nothing is going on start expand check
+ */
+ case 2:
+ /**
+ * A shrink is running, do expand check anyway
+ * (to reset expandFlag)
+ */
+ fragrecptr.p->expandFlag = 2;
+ signal->theData[0] = fragrecptr.i;
+ signal->theData[1] = fragrecptr.p->p;
+ signal->theData[2] = fragrecptr.p->maxp;
+ sendSignal(cownBlockref, GSN_EXPANDCHECK2, signal, 3, JBB);
+ break;
+ }
+ }
+}
+
+void Dbacc::execDEBUG_SIG(Signal* signal)
+{
+ jamEntry();
+ expPageptr.i = signal->theData[0];
+
+ progError(__LINE__,
+ ERR_SR_UNDOLOG);
+ return;
+}//Dbacc::execDEBUG_SIG()
+
+/* --------------------------------------------------------------------------------- */
+/* EXPANDCONTAINER */
+/* INPUT: EXC_PAGEPTR (POINTER TO THE ACTIVE PAGE RECORD) */
+/* CEXC_PAGEINDEX (INDEX OF THE BUCKET). */
+/* */
+/* DESCRIPTION: THE HASH VALUE OF ALL ELEMENTS IN THE CONTAINER WILL BE */
+/* CHECKED. SOME OF THIS ELEMENTS HAVE TO MOVE TO THE NEW CONTAINER */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::expandcontainer(Signal* signal)
+{
+ Uint32 texcHashvalue;
+ Uint32 texcTmp;
+ Uint32 texcIndex;
+ Uint32 guard20;
+
+ cexcPrevpageptr = RNIL;
+ cexcPrevconptr = 0;
+ cexcForward = ZTRUE;
+ EXP_CONTAINER_LOOP:
+ cexcContainerptr = (cexcPageindex << ZSHIFT_PLUS) - (cexcPageindex << ZSHIFT_MINUS);
+ if (cexcForward == ZTRUE) {
+ jam();
+ cexcContainerptr = cexcContainerptr + ZHEAD_SIZE;
+ cexcElementptr = cexcContainerptr + ZCON_HEAD_SIZE;
+ } else {
+ jam();
+ cexcContainerptr = ((cexcContainerptr + ZHEAD_SIZE) + ZBUF_SIZE) - ZCON_HEAD_SIZE;
+ cexcElementptr = cexcContainerptr - 1;
+ }//if
+ arrGuard(cexcContainerptr, 2048);
+ cexcContainerhead = excPageptr.p->word32[cexcContainerptr];
+ cexcContainerlen = cexcContainerhead >> 26;
+ cexcMovedLen = ZCON_HEAD_SIZE;
+ if (cexcContainerlen <= ZCON_HEAD_SIZE) {
+ ndbrequire(cexcContainerlen >= ZCON_HEAD_SIZE);
+ jam();
+ goto NEXT_ELEMENT;
+ }//if
+ NEXT_ELEMENT_LOOP:
+ idrOperationRecPtr.i = RNIL;
+ ptrNull(idrOperationRecPtr);
+ /* --------------------------------------------------------------------------------- */
+ /* CEXC_PAGEINDEX PAGE INDEX OF CURRENT CONTAINER BEING EXAMINED. */
+ /* CEXC_CONTAINERPTR INDEX OF CURRENT CONTAINER BEING EXAMINED. */
+ /* CEXC_ELEMENTPTR INDEX OF CURRENT ELEMENT BEING EXAMINED. */
+ /* EXC_PAGEPTR PAGE WHERE CURRENT ELEMENT RESIDES. */
+ /* CEXC_PREVPAGEPTR PAGE OF PREVIOUS CONTAINER. */
+ /* CEXC_PREVCONPTR INDEX OF PREVIOUS CONTAINER */
+ /* CEXC_FORWARD DIRECTION OF CURRENT CONTAINER */
+ /* --------------------------------------------------------------------------------- */
+ arrGuard(cexcElementptr, 2048);
+ tidrElemhead = excPageptr.p->word32[cexcElementptr];
+ if (ElementHeader::getUnlocked(tidrElemhead)){
+ jam();
+ texcHashvalue = ElementHeader::getHashValuePart(tidrElemhead);
+ } else {
+ jam();
+ idrOperationRecPtr.i = ElementHeader::getOpPtrI(tidrElemhead);
+ ptrCheckGuard(idrOperationRecPtr, coprecsize, operationrec);
+ texcHashvalue = idrOperationRecPtr.p->hashvaluePart;
+ if ((fragrecptr.p->createLcp == ZTRUE) &&
+ (((texcHashvalue >> fragrecptr.p->hashcheckbit) & 1) != 0)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // During local checkpoints we must ensure that we restore the element header in
+ // unlocked state and with the hash value part there with tuple status zeroed.
+ // Otherwise a later insert over the same element will write an UNDO log that will
+ // ensure that the now removed element is restored together with its locked element
+ // header and without the hash value part.
+ /* --------------------------------------------------------------------------------- */
+ const Uint32 hv = idrOperationRecPtr.p->hashvaluePart;
+ const Uint32 eh = ElementHeader::setUnlocked(hv, 0);
+ excPageptr.p->word32[cexcElementptr] = eh;
+ }//if
+ }//if
+ if (((texcHashvalue >> fragrecptr.p->hashcheckbit) & 1) == 0) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THIS ELEMENT IS NOT TO BE MOVED. WE CALCULATE THE WHEREABOUTS OF THE NEXT */
+ /* ELEMENT AND PROCEED WITH THAT OR END THE SEARCH IF THERE ARE NO MORE */
+ /* ELEMENTS IN THIS CONTAINER. */
+ /* --------------------------------------------------------------------------------- */
+ goto NEXT_ELEMENT;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* THE HASH BIT WAS SET AND WE SHALL MOVE THIS ELEMENT TO THE NEW BUCKET. */
+ /* WE START BY READING THE ELEMENT TO BE ABLE TO INSERT IT INTO THE NEW BUCKET.*/
+ /* THEN WE INSERT THE ELEMENT INTO THE NEW BUCKET. THE NEXT STEP IS TO DELETE */
+ /* THE ELEMENT FROM THIS BUCKET. THIS IS PERFORMED BY REPLACING IT WITH THE */
+ /* LAST ELEMENT IN THE BUCKET. IF THIS ELEMENT IS TO BE MOVED WE MOVE IT AND */
+ /* GET THE LAST ELEMENT AGAIN UNTIL WE EITHER FIND ONE THAT STAYS OR THIS */
+ /* ELEMENT IS THE LAST ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ texcTmp = cexcElementptr + cexcForward;
+ guard20 = fragrecptr.p->localkeylen - 1;
+ for (texcIndex = 0; texcIndex <= guard20; texcIndex++) {
+ arrGuard(texcIndex, 2);
+ arrGuard(texcTmp, 2048);
+ clocalkey[texcIndex] = excPageptr.p->word32[texcTmp];
+ texcTmp = texcTmp + cexcForward;
+ }//for
+ tidrPageindex = fragrecptr.p->expReceiveIndex;
+ idrPageptr.i = fragrecptr.p->expReceivePageptr;
+ ptrCheckGuard(idrPageptr, cpagesize, page8);
+ tidrForward = fragrecptr.p->expReceiveForward;
+ insertElement(signal);
+ fragrecptr.p->expReceiveIndex = tidrPageindex;
+ fragrecptr.p->expReceivePageptr = idrPageptr.i;
+ fragrecptr.p->expReceiveForward = tidrForward;
+ REMOVE_LAST_LOOP:
+ jam();
+ lastPageptr.i = excPageptr.i;
+ lastPageptr.p = excPageptr.p;
+ tlastContainerptr = cexcContainerptr;
+ lastPrevpageptr.i = cexcPrevpageptr;
+ ptrCheck(lastPrevpageptr, cpagesize, page8);
+ tlastPrevconptr = cexcPrevconptr;
+ arrGuard(tlastContainerptr, 2048);
+ tlastContainerhead = lastPageptr.p->word32[tlastContainerptr];
+ tlastContainerlen = tlastContainerhead >> 26;
+ tlastForward = cexcForward;
+ tlastPageindex = cexcPageindex;
+ getLastAndRemove(signal);
+ if (excPageptr.i == lastPageptr.i) {
+ if (cexcElementptr == tlastElementptr) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE CURRENT ELEMENT WAS ALSO THE LAST ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* THE CURRENT ELEMENT WAS NOT THE LAST ELEMENT. IF THE LAST ELEMENT SHOULD */
+ /* STAY WE COPY IT TO THE POSITION OF THE CURRENT ELEMENT, OTHERWISE WE INSERT */
+ /* INTO THE NEW BUCKET, REMOVE IT AND TRY WITH THE NEW LAST ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ idrOperationRecPtr.i = RNIL;
+ ptrNull(idrOperationRecPtr);
+ arrGuard(tlastElementptr, 2048);
+ tidrElemhead = lastPageptr.p->word32[tlastElementptr];
+ if (ElementHeader::getUnlocked(tidrElemhead)) {
+ jam();
+ texcHashvalue = ElementHeader::getHashValuePart(tidrElemhead);
+ } else {
+ jam();
+ idrOperationRecPtr.i = ElementHeader::getOpPtrI(tidrElemhead);
+ ptrCheckGuard(idrOperationRecPtr, coprecsize, operationrec);
+ texcHashvalue = idrOperationRecPtr.p->hashvaluePart;
+ if ((fragrecptr.p->createLcp == ZTRUE) &&
+ (((texcHashvalue >> fragrecptr.p->hashcheckbit) & 1) != 0)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // During local checkpoints we must ensure that we restore the element header in
+ // unlocked state and with the hash value part there with tuple status zeroed.
+ // Otherwise a later insert over the same element will write an UNDO log that will
+ // ensure that the now removed element is restored together with its locked element
+ // header and without the hash value part.
+ /* --------------------------------------------------------------------------------- */
+ const Uint32 hv = idrOperationRecPtr.p->hashvaluePart;
+ const Uint32 eh = ElementHeader::setUnlocked(hv, 0);
+ lastPageptr.p->word32[tlastElementptr] = eh;
+ }//if
+ }//if
+ if (((texcHashvalue >> fragrecptr.p->hashcheckbit) & 1) == 0) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST ELEMENT IS NOT TO BE MOVED. WE COPY IT TO THE CURRENT ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ delPageptr = excPageptr;
+ tdelContainerptr = cexcContainerptr;
+ tdelForward = cexcForward;
+ tdelElementptr = cexcElementptr;
+ deleteElement(signal);
+ } else {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST ELEMENT IS ALSO TO BE MOVED. */
+ /* --------------------------------------------------------------------------------- */
+ texcTmp = tlastElementptr + tlastForward;
+ for (texcIndex = 0; texcIndex < fragrecptr.p->localkeylen; texcIndex++) {
+ arrGuard(texcIndex, 2);
+ arrGuard(texcTmp, 2048);
+ clocalkey[texcIndex] = lastPageptr.p->word32[texcTmp];
+ texcTmp = texcTmp + tlastForward;
+ }//for
+ tidrPageindex = fragrecptr.p->expReceiveIndex;
+ idrPageptr.i = fragrecptr.p->expReceivePageptr;
+ ptrCheckGuard(idrPageptr, cpagesize, page8);
+ tidrForward = fragrecptr.p->expReceiveForward;
+ insertElement(signal);
+ fragrecptr.p->expReceiveIndex = tidrPageindex;
+ fragrecptr.p->expReceivePageptr = idrPageptr.i;
+ fragrecptr.p->expReceiveForward = tidrForward;
+ goto REMOVE_LAST_LOOP;
+ }//if
+ NEXT_ELEMENT:
+ arrGuard(cexcContainerptr, 2048);
+ cexcContainerhead = excPageptr.p->word32[cexcContainerptr];
+ cexcMovedLen = cexcMovedLen + fragrecptr.p->elementLength;
+ if ((cexcContainerhead >> 26) > cexcMovedLen) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE HAVE NOT YET MOVED THE COMPLETE CONTAINER. WE PROCEED WITH THE NEXT */
+ /* ELEMENT IN THE CONTAINER. IT IS IMPORTANT TO READ THE CONTAINER LENGTH */
+ /* FROM THE CONTAINER HEADER SINCE IT MIGHT CHANGE BY REMOVING THE LAST */
+ /* ELEMENT IN THE BUCKET. */
+ /* --------------------------------------------------------------------------------- */
+ cexcElementptr = cexcElementptr + (cexcForward * fragrecptr.p->elementLength);
+ goto NEXT_ELEMENT_LOOP;
+ }//if
+ if (((cexcContainerhead >> 7) & 3) != 0) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WE PROCEED TO THE NEXT CONTAINER IN THE BUCKET. */
+ /* --------------------------------------------------------------------------------- */
+ cexcPrevpageptr = excPageptr.i;
+ cexcPrevconptr = cexcContainerptr;
+ nextcontainerinfoExp(signal);
+ goto EXP_CONTAINER_LOOP;
+ }//if
+}//Dbacc::expandcontainer()
+
+/* ******************--------------------------------------------------------------- */
+/* SHRINKCHECK JOIN BUCKET ORD */
+/* SENDER: ACC, LEVEL B */
+/* INPUT: FRAGRECPTR, POINTS TO A FRAGMENT RECORD. */
+/* DESCRIPTION: TWO BUCKET OF A FRAGMENT PAGE WILL BE JOINED TOGETHER */
+/* ACCORDING TO LH3. */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* SHRINKCHECK JOIN BUCKET ORD */
+/* ******************------------------------------+ */
+/* SENDER: ACC, LEVEL B */
+/* TWO BUCKETS OF THE FRAGMENT */
+/* WILL BE JOINED ACORDING TO LH3 */
+/* AND COMMIT TRANSACTION PROCESS */
+/* WILL BE CONTINUED */
+Uint32 Dbacc::checkScanShrink(Signal* signal)
+{
+ Uint32 Ti;
+ Uint32 TreturnCode = 0;
+ Uint32 TPageIndex;
+ Uint32 TDirInd;
+ Uint32 TmergeDest;
+ Uint32 TmergeSource;
+ Uint32 TreleaseScanBucket;
+ Uint32 TreleaseInd = 0;
+ Uint32 TreleaseScanIndicator[4];
+ DirectoryarrayPtr TDirptr;
+ DirRangePtr TDirRangePtr;
+ Page8Ptr TPageptr;
+ ScanRecPtr TscanPtr;
+ RootfragmentrecPtr Trootfragrecptr;
+
+ Trootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(Trootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (fragrecptr.p->p == 0) {
+ jam();
+ TmergeDest = fragrecptr.p->maxp >> 1;
+ } else {
+ jam();
+ TmergeDest = fragrecptr.p->p - 1;
+ }//if
+ TmergeSource = fragrecptr.p->maxp + fragrecptr.p->p;
+ for (Ti = 0; Ti < 4; Ti++) {
+ TreleaseScanIndicator[Ti] = 0;
+ if (Trootfragrecptr.p->scan[Ti] != RNIL) {
+ TscanPtr.i = Trootfragrecptr.p->scan[Ti];
+ ptrCheckGuard(TscanPtr, cscanRecSize, scanRec);
+ if (TscanPtr.p->activeLocalFrag == fragrecptr.i) {
+ //-------------------------------------------------------------
+ // A scan is ongoing on this particular local fragment. We have
+ // to check its current state.
+ //-------------------------------------------------------------
+ if (TscanPtr.p->scanBucketState == ScanRec::FIRST_LAP) {
+ jam();
+ if ((TmergeDest == TscanPtr.p->nextBucketIndex) ||
+ (TmergeSource == TscanPtr.p->nextBucketIndex)) {
+ jam();
+ //-------------------------------------------------------------
+ // We are currently scanning one of the buckets involved in the
+ // merge. We cannot merge while simultaneously performing a scan.
+ // We have to pass this offer for merging the buckets.
+ //-------------------------------------------------------------
+ TreturnCode = 1;
+ return TreturnCode;
+ } else if (TmergeDest < TscanPtr.p->nextBucketIndex) {
+ jam();
+ TreleaseScanIndicator[Ti] = 1;
+ TreleaseInd = 1;
+ }//if
+ } else if (TscanPtr.p->scanBucketState == ScanRec::SECOND_LAP) {
+ jam();
+ //-------------------------------------------------------------
+ // We are performing a second lap to handle buckets that was
+ // merged during the first lap of scanning. During this second
+ // lap we do not allow any splits or merges.
+ //-------------------------------------------------------------
+ TreturnCode = 1;
+ return TreturnCode;
+ } else if (TscanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED) {
+ jam();
+ //-------------------------------------------------------------
+ // The scan is completed and we can thus go ahead and perform
+ // the split.
+ //-------------------------------------------------------------
+ } else {
+ jam();
+ sendSystemerror(signal);
+ return TreturnCode;
+ }//if
+ }//if
+ }//if
+ }//for
+ if (TreleaseInd == 1) {
+ jam();
+ TreleaseScanBucket = TmergeSource;
+ TDirRangePtr.i = fragrecptr.p->directory;
+ TPageIndex = TreleaseScanBucket & ((1 << fragrecptr.p->k) - 1); /* PAGE INDEX OBS K = 6 */
+ TDirInd = TreleaseScanBucket >> fragrecptr.p->k; /* DIRECTORY INDEX OBS K = 6 */
+ ptrCheckGuard(TDirRangePtr, cdirrangesize, dirRange);
+ arrGuard((TDirInd >> 8), 256);
+ TDirptr.i = TDirRangePtr.p->dirArray[TDirInd >> 8];
+ ptrCheckGuard(TDirptr, cdirarraysize, directoryarray);
+ TPageptr.i = TDirptr.p->pagep[TDirInd & 0xff];
+ ptrCheckGuard(TPageptr, cpagesize, page8);
+ for (Ti = 0; Ti < 4; Ti++) {
+ if (TreleaseScanIndicator[Ti] == 1) {
+ jam();
+ scanPtr.i = Trootfragrecptr.p->scan[Ti];
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+ rsbPageidptr.i = TPageptr.i;
+ rsbPageidptr.p = TPageptr.p;
+ trsbPageindex = TPageIndex;
+ releaseScanBucket(signal);
+ if (TmergeDest < scanPtr.p->minBucketIndexToRescan) {
+ jam();
+ //-------------------------------------------------------------
+ // We have to keep track of the starting bucket to Rescan in the
+ // second lap.
+ //-------------------------------------------------------------
+ scanPtr.p->minBucketIndexToRescan = TmergeDest;
+ }//if
+ if (TmergeDest > scanPtr.p->maxBucketIndexToRescan) {
+ jam();
+ //-------------------------------------------------------------
+ // We have to keep track of the ending bucket to Rescan in the
+ // second lap.
+ //-------------------------------------------------------------
+ scanPtr.p->maxBucketIndexToRescan = TmergeDest;
+ }//if
+ }//if
+ }//for
+ }//if
+ return TreturnCode;
+}//Dbacc::checkScanShrink()
+
+void Dbacc::execSHRINKCHECK2(Signal* signal)
+{
+ Uint32 tshrTmp1;
+
+ jamEntry();
+ fragrecptr.i = signal->theData[0];
+ Uint32 oldFlag = signal->theData[3];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->expandFlag = oldFlag;
+ tresult = 0; /* 0= FALSE,1= TRUE,> ZLIMIT_OF_ERROR =ERRORCODE */
+ if (fragrecptr.p->slack <= fragrecptr.p->slackCheck) {
+ jam();
+ /* TIME FOR JOIN BUCKETS PROCESS */
+ /*--------------------------------------------------------------*/
+ /* NO LONGER NECESSARY TO SHRINK THE FRAGMENT. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ if (fragrecptr.p->slack > (1u << 31)) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* THE SLACK IS NEGATIVE, IN THIS CASE WE WILL NOT NEED ANY */
+ /* SHRINK. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ texpDirInd = (fragrecptr.p->maxp + fragrecptr.p->p) >> fragrecptr.p->k;
+ if (((fragrecptr.p->maxp + fragrecptr.p->p) & ((1 << fragrecptr.p->k) - 1)) == 0) {
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (fragrecptr.p->fragState == LCP_SEND_PAGES) {
+ if (fragrecptr.p->lcpMaxDirIndex > texpDirInd) {
+ if (fragrecptr.p->lcpDirIndex <= texpDirInd) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* WE DO NOT ALLOW ANY SHRINKS THAT REMOVE PAGES THAT ARE */
+ /* NEEDED AS PART OF THE LOCAL CHECKPOINT. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+ }//if
+ }//if
+ }//if
+ if (fragrecptr.p->firstOverflowRec == RNIL) {
+ jam();
+ allocOverflowPage(signal);
+ if (tresult > ZLIMIT_OF_ERROR) {
+ jam();
+ return;
+ }//if
+ }//if
+ if (cfirstfreepage == RNIL) {
+ if (cfreepage >= cpagesize) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* WE HAVE TO STOP THE SHRINK PROCESS SINCE THERE ARE NO FREE */
+ /* PAGES. THIS MEANS THAT WE COULD BE FORCED TO CRASH SINCE WE */
+ /* CANNOT COMPLETE THE SHRINK. TO AVOID THE CRASH WE EXIT HERE. */
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+ if (checkScanShrink(signal) == 1) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // A scan state was inconsistent with performing a shrink
+ // operation.
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_EXPAND) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // We did not have enough undo log buffers to start up an
+ // shrink operation
+ /*--------------------------------------------------------------*/
+ return;
+ }//if
+ }//if
+ if (fragrecptr.p->p == 0) {
+ jam();
+ fragrecptr.p->maxp = fragrecptr.p->maxp >> 1;
+ fragrecptr.p->p = fragrecptr.p->maxp;
+ fragrecptr.p->lhdirbits--;
+ fragrecptr.p->hashcheckbit--;
+ } else {
+ jam();
+ fragrecptr.p->p--;
+ }//if
+
+ /*--------------------------------------------------------------------------*/
+ /* WE START BY FINDING THE NECESSARY INFORMATION OF THE BUCKET TO BE */
+ /* REMOVED WHICH WILL SEND ITS ELEMENTS TO THE RECEIVING BUCKET. */
+ /*--------------------------------------------------------------------------*/
+ expDirRangePtr.i = fragrecptr.p->directory;
+ cexcPageindex = ((fragrecptr.p->maxp + fragrecptr.p->p) + 1) & ((1 << fragrecptr.p->k) - 1);
+ texpDirInd = ((fragrecptr.p->maxp + fragrecptr.p->p) + 1) >> fragrecptr.p->k;
+ texpDirRangeIndex = texpDirInd >> 8;
+ texpDirPageIndex = texpDirInd & 0xff;
+ ptrCheckGuard(expDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(texpDirRangeIndex, 256);
+ expDirptr.i = expDirRangePtr.p->dirArray[texpDirRangeIndex];
+ ptrCheckGuard(expDirptr, cdirarraysize, directoryarray);
+ excPageptr.i = expDirptr.p->pagep[texpDirPageIndex];
+ fragrecptr.p->expSenderDirptr = expDirptr.i;
+ fragrecptr.p->expSenderIndex = cexcPageindex;
+ fragrecptr.p->expSenderPageptr = excPageptr.i;
+ fragrecptr.p->expSenderDirIndex = texpDirInd;
+ /*--------------------------------------------------------------------------*/
+ /* WE NOW PROCEED BY FINDING THE NECESSARY INFORMATION ABOUT THE */
+ /* RECEIVING BUCKET. */
+ /*--------------------------------------------------------------------------*/
+ expDirRangePtr.i = fragrecptr.p->directory;
+ texpReceivedBucket = fragrecptr.p->p >> fragrecptr.p->k;
+ ptrCheckGuard(expDirRangePtr, cdirrangesize, dirRange);
+ arrGuard((texpReceivedBucket >> 8), 256);
+ expDirptr.i = expDirRangePtr.p->dirArray[texpReceivedBucket >> 8];
+ ptrCheckGuard(expDirptr, cdirarraysize, directoryarray);
+ fragrecptr.p->expReceivePageptr = expDirptr.p->pagep[texpReceivedBucket & 0xff];
+ fragrecptr.p->expReceiveIndex = fragrecptr.p->p & ((1 << fragrecptr.p->k) - 1);
+ fragrecptr.p->expReceiveForward = ZTRUE;
+ if (excPageptr.i == RNIL) {
+ jam();
+ endofshrinkbucketLab(signal); /* EMPTY BUCKET */
+ return;
+ }//if
+ /*--------------------------------------------------------------------------*/
+ /* INITIALISE THE VARIABLES FOR THE SHRINK PROCESS. */
+ /*--------------------------------------------------------------------------*/
+ ptrCheckGuard(excPageptr, cpagesize, page8);
+ cexcForward = ZTRUE;
+ cexcContainerptr = (cexcPageindex << ZSHIFT_PLUS) - (cexcPageindex << ZSHIFT_MINUS);
+ cexcContainerptr = cexcContainerptr + ZHEAD_SIZE;
+ arrGuard(cexcContainerptr, 2048);
+ cexcContainerhead = excPageptr.p->word32[cexcContainerptr];
+ cexcContainerlen = cexcContainerhead >> 26;
+ if (cexcContainerlen <= ZCON_HEAD_SIZE) {
+ ndbrequire(cexcContainerlen == ZCON_HEAD_SIZE);
+ } else {
+ jam();
+ shrinkcontainer(signal);
+ }//if
+ /*--------------------------------------------------------------------------*/
+ /* THIS CONTAINER IS NOT YET EMPTY AND WE REMOVE ALL THE ELEMENTS. */
+ /*--------------------------------------------------------------------------*/
+ if (((cexcContainerhead >> 10) & 1) == 1) {
+ jam();
+ rlPageptr = excPageptr;
+ trlPageindex = cexcPageindex;
+ trlRelCon = ZFALSE;
+ turlIndex = cexcContainerptr + (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ releaseRightlist(signal);
+ }//if
+ tshrTmp1 = ZCON_HEAD_SIZE;
+ tshrTmp1 = tshrTmp1 << 26;
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ datapageptr.p = excPageptr.p;
+ cundoinfolength = 1;
+ cundoElemIndex = cexcContainerptr;
+ undoWritingProcess(signal);
+ }//if
+ dbgWord32(excPageptr, cexcContainerptr, tshrTmp1);
+ arrGuard(cexcContainerptr, 2048);
+ excPageptr.p->word32[cexcContainerptr] = tshrTmp1;
+ if (((cexcContainerhead >> 7) & 0x3) == 0) {
+ jam();
+ endofshrinkbucketLab(signal);
+ return;
+ }//if
+ nextcontainerinfoExp(signal);
+ do {
+ cexcContainerptr = (cexcPageindex << ZSHIFT_PLUS) - (cexcPageindex << ZSHIFT_MINUS);
+ if (cexcForward == ZTRUE) {
+ jam();
+ cexcContainerptr = cexcContainerptr + ZHEAD_SIZE;
+ } else {
+ jam();
+ cexcContainerptr = ((cexcContainerptr + ZHEAD_SIZE) + ZBUF_SIZE) - ZCON_HEAD_SIZE;
+ }//if
+ arrGuard(cexcContainerptr, 2048);
+ cexcContainerhead = excPageptr.p->word32[cexcContainerptr];
+ cexcContainerlen = cexcContainerhead >> 26;
+ ndbrequire(cexcContainerlen > ZCON_HEAD_SIZE);
+ /*--------------------------------------------------------------------------*/
+ /* THIS CONTAINER IS NOT YET EMPTY AND WE REMOVE ALL THE ELEMENTS. */
+ /*--------------------------------------------------------------------------*/
+ shrinkcontainer(signal);
+ cexcPrevpageptr = excPageptr.i;
+ cexcPrevpageindex = cexcPageindex;
+ cexcPrevforward = cexcForward;
+ if (((cexcContainerhead >> 7) & 0x3) != 0) {
+ jam();
+ /*--------------------------------------------------------------------------*/
+ /* WE MUST CALL THE NEXT CONTAINER INFO ROUTINE BEFORE WE RELEASE THE */
+ /* CONTAINER SINCE THE RELEASE WILL OVERWRITE THE NEXT POINTER. */
+ /*--------------------------------------------------------------------------*/
+ nextcontainerinfoExp(signal);
+ }//if
+ rlPageptr.i = cexcPrevpageptr;
+ ptrCheckGuard(rlPageptr, cpagesize, page8);
+ trlPageindex = cexcPrevpageindex;
+ if (cexcPrevforward == ZTRUE) {
+ jam();
+ if (((cexcContainerhead >> 10) & 1) == 1) {
+ jam();
+ trlRelCon = ZFALSE;
+ turlIndex = cexcContainerptr + (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ releaseRightlist(signal);
+ }//if
+ trlRelCon = ZTRUE;
+ tullIndex = cexcContainerptr;
+ releaseLeftlist(signal);
+ } else {
+ jam();
+ if (((cexcContainerhead >> 10) & 1) == 1) {
+ jam();
+ trlRelCon = ZFALSE;
+ tullIndex = cexcContainerptr - (ZBUF_SIZE - ZCON_HEAD_SIZE);
+ releaseLeftlist(signal);
+ }//if
+ trlRelCon = ZTRUE;
+ turlIndex = cexcContainerptr;
+ releaseRightlist(signal);
+ }//if
+ } while (((cexcContainerhead >> 7) & 0x3) != 0);
+ endofshrinkbucketLab(signal);
+ return;
+}//Dbacc::execSHRINKCHECK2()
+
+void Dbacc::endofshrinkbucketLab(Signal* signal)
+{
+ fragrecptr.p->expandCounter--;
+ fragrecptr.p->slack -= fragrecptr.p->maxloadfactor;
+ if (fragrecptr.p->expSenderIndex == 0) {
+ jam();
+ fragrecptr.p->dirsize--;
+ if (fragrecptr.p->expSenderPageptr != RNIL) {
+ jam();
+ rpPageptr.i = fragrecptr.p->expSenderPageptr;
+ ptrCheckGuard(rpPageptr, cpagesize, page8);
+ releasePage(signal);
+ expDirptr.i = fragrecptr.p->expSenderDirptr;
+ ptrCheckGuard(expDirptr, cdirarraysize, directoryarray);
+ expDirptr.p->pagep[fragrecptr.p->expSenderDirIndex & 0xff] = RNIL;
+ }//if
+ if (((((fragrecptr.p->p + fragrecptr.p->maxp) + 1) >> fragrecptr.p->k) & 0xff) == 0) {
+ jam();
+ rdDirptr.i = fragrecptr.p->expSenderDirptr;
+ releaseDirectory(signal);
+ expDirRangePtr.i = fragrecptr.p->directory;
+ ptrCheckGuard(expDirRangePtr, cdirrangesize, dirRange);
+ arrGuard((fragrecptr.p->expSenderDirIndex >> 8), 256);
+ expDirRangePtr.p->dirArray[fragrecptr.p->expSenderDirIndex >> 8] = RNIL;
+ }//if
+ }//if
+ if (fragrecptr.p->slack < (1u << 31)) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* THE SLACK IS POSITIVE, IN THIS CASE WE WILL CHECK WHETHER */
+ /* WE WILL CONTINUE PERFORM ANOTHER SHRINK. */
+ /*--------------------------------------------------------------*/
+ Uint32 noOfBuckets = (fragrecptr.p->maxp + 1) + fragrecptr.p->p;
+ Uint32 Thysteresis = fragrecptr.p->maxloadfactor - fragrecptr.p->minloadfactor;
+ fragrecptr.p->slackCheck = noOfBuckets * Thysteresis;
+ if (fragrecptr.p->slack > Thysteresis) {
+ /*--------------------------------------------------------------*/
+ /* IT IS STILL NECESSARY TO SHRINK THE FRAGMENT MORE. THIS*/
+ /* CAN HAPPEN WHEN A NUMBER OF SHRINKS GET REJECTED */
+ /* DURING A LOCAL CHECKPOINT. WE START A NEW SHRINK */
+ /* IMMEDIATELY FROM HERE WITHOUT WAITING FOR A COMMIT TO */
+ /* START IT. */
+ /*--------------------------------------------------------------*/
+ if (fragrecptr.p->expandCounter > 0) {
+ jam();
+ /*--------------------------------------------------------------*/
+ /* IT IS VERY IMPORTANT TO NOT TRY TO SHRINK MORE THAN */
+ /* WAS EXPANDED. IF MAXP IS SET TO A VALUE BELOW 63 THEN */
+ /* WE WILL LOSE RECORDS SINCE GETDIRINDEX CANNOT HANDLE */
+ /* SHRINKING BELOW 2^K - 1 (NOW 63). THIS WAS A BUG THAT */
+ /* WAS REMOVED 2000-05-12. */
+ /*--------------------------------------------------------------*/
+ signal->theData[0] = fragrecptr.i;
+ signal->theData[1] = fragrecptr.p->p;
+ signal->theData[2] = fragrecptr.p->maxp;
+ signal->theData[3] = fragrecptr.p->expandFlag;
+ ndbrequire(fragrecptr.p->expandFlag < 2);
+ fragrecptr.p->expandFlag = 2;
+ sendSignal(cownBlockref, GSN_SHRINKCHECK2, signal, 4, JBB);
+ }//if
+ }//if
+ }//if
+ ndbrequire(fragrecptr.p->maxp >= (Uint32)((1 << fragrecptr.p->k) - 1));
+ return;
+}//Dbacc::endofshrinkbucketLab()
+
+/* --------------------------------------------------------------------------------- */
+/* SHRINKCONTAINER */
+/* INPUT: EXC_PAGEPTR (POINTER TO THE ACTIVE PAGE RECORD) */
+/* CEXC_CONTAINERLEN (LENGTH OF THE CONTAINER). */
+/* CEXC_CONTAINERPTR (ARRAY INDEX OF THE CONTAINER). */
+/* CEXC_FORWARD (CONTAINER FORWARD (+1) OR BACKWARD (-1)) */
+/* */
+/* DESCRIPTION: ALL ELEMENTS OF THE ACTIVE CONTAINER HAVE TO MOVE TO THE NEW */
+/* CONTAINER. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::shrinkcontainer(Signal* signal)
+{
+ Uint32 tshrElementptr;
+ Uint32 tshrRemLen;
+ Uint32 tshrInc;
+ Uint32 tshrTmp;
+ Uint32 tshrIndex;
+ Uint32 guard21;
+
+ tshrRemLen = cexcContainerlen - ZCON_HEAD_SIZE;
+ tshrInc = fragrecptr.p->elementLength;
+ if (cexcForward == ZTRUE) {
+ jam();
+ tshrElementptr = cexcContainerptr + ZCON_HEAD_SIZE;
+ } else {
+ jam();
+ tshrElementptr = cexcContainerptr - 1;
+ }//if
+ SHR_LOOP:
+ idrOperationRecPtr.i = RNIL;
+ ptrNull(idrOperationRecPtr);
+ /* --------------------------------------------------------------------------------- */
+ /* THE CODE BELOW IS ALL USED TO PREPARE FOR THE CALL TO INSERT_ELEMENT AND */
+ /* HANDLE THE RESULT FROM INSERT_ELEMENT. INSERT_ELEMENT INSERTS THE ELEMENT */
+ /* INTO ANOTHER BUCKET. */
+ /* --------------------------------------------------------------------------------- */
+ arrGuard(tshrElementptr, 2048);
+ tidrElemhead = excPageptr.p->word32[tshrElementptr];
+ if (ElementHeader::getLocked(tidrElemhead)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* IF THE ELEMENT IS LOCKED WE MUST UPDATE THE ELEMENT INFO IN THE OPERATION */
+ /* RECORD OWNING THE LOCK. WE DO THIS BY READING THE OPERATION RECORD POINTER */
+ /* FROM THE ELEMENT HEADER. */
+ /* --------------------------------------------------------------------------------- */
+ idrOperationRecPtr.i = ElementHeader::getOpPtrI(tidrElemhead);
+ ptrCheckGuard(idrOperationRecPtr, coprecsize, operationrec);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // During local checkpoints we must ensure that we restore the element header in
+ // unlocked state and with the hash value part there with tuple status zeroed.
+ // Otherwise a later insert over the same element will write an UNDO log that will
+ // ensure that the now removed element is restored together with its locked element
+ // header and without the hash value part.
+ /* --------------------------------------------------------------------------------- */
+ const Uint32 hv = idrOperationRecPtr.p->hashvaluePart;
+ const Uint32 eh = ElementHeader::setUnlocked(hv, 0);
+ excPageptr.p->word32[tshrElementptr] = eh;
+ }//if
+ }//if
+ tshrTmp = tshrElementptr + cexcForward;
+ guard21 = fragrecptr.p->localkeylen - 1;
+ for (tshrIndex = 0; tshrIndex <= guard21; tshrIndex++) {
+ arrGuard(tshrIndex, 2);
+ arrGuard(tshrTmp, 2048);
+ clocalkey[tshrIndex] = excPageptr.p->word32[tshrTmp];
+ tshrTmp = tshrTmp + cexcForward;
+ }//for
+ tidrPageindex = fragrecptr.p->expReceiveIndex;
+ idrPageptr.i = fragrecptr.p->expReceivePageptr;
+ ptrCheckGuard(idrPageptr, cpagesize, page8);
+ tidrForward = fragrecptr.p->expReceiveForward;
+ insertElement(signal);
+ /* --------------------------------------------------------------------------------- */
+ /* TAKE CARE OF RESULT FROM INSERT_ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ fragrecptr.p->expReceiveIndex = tidrPageindex;
+ fragrecptr.p->expReceivePageptr = idrPageptr.i;
+ fragrecptr.p->expReceiveForward = tidrForward;
+ if (tshrRemLen < tshrInc) {
+ jam();
+ sendSystemerror(signal);
+ }//if
+ tshrRemLen = tshrRemLen - tshrInc;
+ if (tshrRemLen != 0) {
+ jam();
+ tshrElementptr = tshrTmp;
+ goto SHR_LOOP;
+ }//if
+}//Dbacc::shrinkcontainer()
+
+/* --------------------------------------------------------------------------------- */
+/* NEXTCONTAINERINFO_EXP */
+/* DESCRIPTION:THE CONTAINER HEAD WILL BE CHECKED TO CALCULATE INFORMATION */
+/* ABOUT NEXT CONTAINER IN THE BUCKET. */
+/* INPUT: CEXC_CONTAINERHEAD */
+/* CEXC_CONTAINERPTR */
+/* EXC_PAGEPTR */
+/* OUTPUT: */
+/* CEXC_PAGEINDEX (INDEX FROM WHICH PAGE INDEX CAN BE CALCULATED. */
+/* EXC_PAGEPTR (PAGE REFERENCE OF NEXT CONTAINER) */
+/* CEXC_FORWARD */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::nextcontainerinfoExp(Signal* signal)
+{
+ tnciNextSamePage = (cexcContainerhead >> 9) & 0x1; /* CHECK BIT FOR CHECKING WHERE */
+ /* THE NEXT CONTAINER IS IN THE SAME PAGE */
+ cexcPageindex = cexcContainerhead & 0x7f; /* NEXT CONTAINER PAGE INDEX 7 BITS */
+ if (((cexcContainerhead >> 7) & 3) == ZLEFT) {
+ jam();
+ cexcForward = ZTRUE;
+ } else if (((cexcContainerhead >> 7) & 3) == ZRIGHT) {
+ jam();
+ cexcForward = cminusOne;
+ } else {
+ jam();
+ sendSystemerror(signal);
+ cexcForward = 0; /* DUMMY FOR COMPILER */
+ }//if
+ if (tnciNextSamePage == ZFALSE) {
+ jam();
+ /* NEXT CONTAINER IS IN AN OVERFLOW PAGE */
+ arrGuard(cexcContainerptr + 1, 2048);
+ tnciTmp = excPageptr.p->word32[cexcContainerptr + 1];
+ nciOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ ptrCheckGuard(nciOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard((tnciTmp >> 8), 256);
+ nciOverflowDirptr.i = nciOverflowrangeptr.p->dirArray[tnciTmp >> 8];
+ ptrCheckGuard(nciOverflowDirptr, cdirarraysize, directoryarray);
+ excPageptr.i = nciOverflowDirptr.p->pagep[tnciTmp & 0xff];
+ ptrCheckGuard(excPageptr, cpagesize, page8);
+ }//if
+}//Dbacc::nextcontainerinfoExp()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF EXPAND/SHRINK MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* LOCAL CHECKPOINT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* LCP_FRAGIDREQ */
+/* SENDER: LQH, LEVEL B */
+/* ENTER LCP_FRAGIDREQ WITH */
+/* TUSERPTR LQH CONNECTION PTR */
+/* TUSERBLOCKREF, LQH BLOCK REFERENCE */
+/* TCHECKPOINTID, THE CHECKPOINT NUMBER TO USE */
+/* (E.G. 1,2 OR 3) */
+/* TABPTR, TABLE ID = TABLE RECORD POINTER */
+/* TFID ROOT FRAGMENT ID */
+/* CACTIVE_UNDO_FILE_VERSION UNDO FILE VERSION 0,1,2 OR 3. */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* LCP_FRAGIDREQ REQUEST FOR LIST OF STOPED OPERATION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execLCP_FRAGIDREQ(Signal* signal)
+{
+ jamEntry();
+ tuserptr = signal->theData[0]; /* LQH CONNECTION PTR */
+ tuserblockref = signal->theData[1]; /* LQH BLOCK REFERENCE */
+ tcheckpointid = signal->theData[2]; /* THE CHECKPOINT NUMBER TO USE */
+ /* (E.G. 1,2 OR 3) */
+ tabptr.i = signal->theData[3]; /* TABLE ID = TABLE RECORD POINTER */
+ ptrCheck(tabptr, ctablesize, tabrec);
+ tfid = signal->theData[4]; /* ROOT FRAGMENT ID */
+ cactiveUndoFileVersion = signal->theData[5]; /* UNDO FILE VERSION 0,1,2 OR 3. */
+ tresult = 0;
+ ndbrequire(getrootfragmentrec(signal, rootfragrecptr, tfid));
+ ndbrequire(rootfragrecptr.p->rootState == ACTIVEROOT);
+ seizeLcpConnectRec(signal);
+ initLcpConnRec(signal);
+ lcpConnectptr.p->rootrecptr = rootfragrecptr.i;
+ rootfragrecptr.p->lcpPtr = lcpConnectptr.i;
+ lcpConnectptr.p->localCheckPid = tcheckpointid;
+ lcpConnectptr.p->lcpstate = LCP_ACTIVE;
+ rootfragrecptr.p->rootState = LCP_CREATION;
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ /* D6 AT FSOPENREQ =#010003FF. */
+ tlfrTmp1 = 0x010003ff; /* FILE TYPE = .DATA ,VERSION OF FILENAME = 1 */
+ tlfrTmp2 = 0x301; /* D7 CREATE, WRITE ONLY, TRUNCATE TO ZERO */
+ ndbrequire(cfsFirstfreeconnect != RNIL);
+ seizeFsConnectRec(signal);
+ fsConnectptr.p->fragrecPtr = fragrecptr.i;
+ fsConnectptr.p->fsState = WAIT_OPEN_DATA_FILE_FOR_WRITE;
+ /* ----------- FILENAME (FILESYSTEM)/D3/DBACC/"T"TABID/"F"FRAGID/"S"VERSIONID.DATA ------------ */
+ /* ************************ */
+ /* FSOPENREQ */
+ /* ************************ */
+ signal->theData[0] = cownBlockref;
+ signal->theData[1] = fsConnectptr.i;
+ signal->theData[2] = tabptr.i; /* TABLE IDENTITY */
+ signal->theData[3] = rootfragrecptr.p->fragmentid[0]; /* FRAGMENT IDENTITY */
+ signal->theData[4] = lcpConnectptr.p->localCheckPid; /* CHECKPOINT ID */
+ signal->theData[5] = tlfrTmp1;
+ signal->theData[6] = tlfrTmp2;
+ sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA);
+ return;
+}//Dbacc::execLCP_FRAGIDREQ()
+
+/* ******************--------------------------------------------------------------- */
+/* FSOPENCONF OPENFILE CONF */
+/* SENDER: FS, LEVEL B */
+/* ENTER FSOPENCONF WITH */
+/* FS_CONNECTPTR, FS_CONNECTION PTR */
+/* TUSERPOINTER, FILE POINTER */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::lcpFsOpenConfLab(Signal* signal)
+{
+ fsConnectptr.p->fsPtr = tuserptr;
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ fragrecptr.p->activeDataFilePage = 1; /* ZERO IS KEPT FOR PAGE_ZERO */
+ fragrecptr.p->fsConnPtr = fsConnectptr.i;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ if (rootfragrecptr.p->fragmentptr[0] == fragrecptr.i) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ ptrCheck(fragrecptr, cfragmentsize, fragmentrec);
+ /* ----------- FILENAME (FILESYSTEM)/D3/DBACC/"T"TABID/"F"FRAGID/"S"VERSIONID.DATA ------------ */
+ /* D6 AT FSOPENREQ =#010003FF. */
+ tlfrTmp1 = 0x010003ff; /* FILE TYPE = .DATA ,VERSION OF FILENAME = 1 */
+ tlfrTmp2 = 0x301; /* D7 CREATE, WRITE ONLY, TRUNCATE TO ZERO */
+ ndbrequire(cfsFirstfreeconnect != RNIL);
+ seizeFsConnectRec(signal);
+ fsConnectptr.p->fragrecPtr = fragrecptr.i;
+ fsConnectptr.p->fsState = WAIT_OPEN_DATA_FILE_FOR_WRITE;
+ /* ************************ */
+ /* FSOPENREQ */
+ /* ************************ */
+ signal->theData[0] = cownBlockref;
+ signal->theData[1] = fsConnectptr.i;
+ signal->theData[2] = rootfragrecptr.p->mytabptr; /* TABLE IDENTITY */
+ signal->theData[3] = rootfragrecptr.p->fragmentid[1]; /* FRAGMENT IDENTITY */
+ signal->theData[4] = lcpConnectptr.p->localCheckPid; /* CHECKPOINT ID */
+ signal->theData[5] = tlfrTmp1;
+ signal->theData[6] = tlfrTmp2;
+ sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA);
+ return;
+ } else {
+ ndbrequire(rootfragrecptr.p->fragmentptr[1] == fragrecptr.i);
+ }//if
+ /*---- BOTH DATA FILES ARE OPEN------*/
+ /* ----IF THE UNDO FILE IS CLOSED , OPEN IT.----- */
+ if (cactiveOpenUndoFsPtr != RNIL) {
+ jam();
+ sendLcpFragidconfLab(signal);
+ return;
+ }//if
+ cactiveUndoFilePage = 0;
+ cprevUndoaddress = cminusOne;
+ cundoposition = 0;
+ clastUndoPageIdWritten = 0;
+ ndbrequire(cfsFirstfreeconnect != RNIL);
+ seizeFsConnectRec(signal);
+ fsConnectptr.p->fsState = WAIT_OPEN_UNDO_LCP;
+ fsConnectptr.p->fsPart = 0; /* FILE INDEX, SECOND FILE IN THE DIRECTORY */
+ cactiveOpenUndoFsPtr = fsConnectptr.i;
+ cactiveRootfrag = rootfragrecptr.i;
+ tlfrTmp1 = 1; /* FILE VERSION */
+ tlfrTmp1 = (tlfrTmp1 << 8) + ZLOCALLOGFILE; /* .LOCLOG = 2 */
+ tlfrTmp1 = (tlfrTmp1 << 8) + 4; /* ROOT DIRECTORY = D4 */
+ tlfrTmp1 = (tlfrTmp1 << 8) + fsConnectptr.p->fsPart; /* P2 */
+ tlfrTmp2 = 0x302; /* D7 CREATE , READ / WRITE , TRUNCATE TO ZERO */
+ /* ---FILE NAME "D4"/"DBACC"/LCP_CONNECTPTR:LOCAL_CHECK_PID/FS_CONNECTPTR:FS_PART".LOCLOG-- */
+ /* ************************ */
+ /* FSOPENREQ */
+ /* ************************ */
+ signal->theData[0] = cownBlockref;
+ signal->theData[1] = fsConnectptr.i;
+ signal->theData[2] = cminusOne; /* #FFFFFFFF */
+ signal->theData[3] = cminusOne; /* #FFFFFFFF */
+ signal->theData[4] = cactiveUndoFileVersion;
+ /* A GROUP OF UNDO FILES WHICH ARE UPDATED */
+ signal->theData[5] = tlfrTmp1;
+ signal->theData[6] = tlfrTmp2;
+ sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA);
+ return;
+}//Dbacc::lcpFsOpenConfLab()
+
+void Dbacc::lcpOpenUndofileConfLab(Signal* signal)
+{
+ ptrGuard(fsConnectptr);
+ fsConnectptr.p->fsState = WAIT_NOTHING;
+ rootfragrecptr.i = cactiveRootfrag;
+ ptrCheck(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ fsConnectptr.p->fsPtr = tuserptr;
+ sendLcpFragidconfLab(signal);
+ return;
+}//Dbacc::lcpOpenUndofileConfLab()
+
+void Dbacc::sendLcpFragidconfLab(Signal* signal)
+{
+ ptrGuard(rootfragrecptr);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ /* ************************ */
+ /* LCP_FRAGIDCONF */
+ /* ************************ */
+ signal->theData[0] = lcpConnectptr.p->lcpUserptr;
+ signal->theData[1] = lcpConnectptr.i;
+ signal->theData[2] = 2;
+ /* NO OF LOCAL FRAGMENTS */
+ signal->theData[3] = rootfragrecptr.p->fragmentid[0];
+ signal->theData[4] = rootfragrecptr.p->fragmentid[1];
+ signal->theData[5] = RNIL;
+ signal->theData[6] = RNIL;
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_LCP_FRAGIDCONF, signal, 7, JBB);
+ return;
+}//Dbacc::sendLcpFragidconfLab()
+
+/* ******************--------------------------------------------------------------- */
+/* LCP_HOLDOPERATION REQUEST FOR LIST OF STOPED OPERATION */
+/* SENDER: LQH, LEVEL B */
+/* ENTER LCP_HOLDOPREQ WITH */
+/* LCP_CONNECTPTR CONNECTION POINTER */
+/* TFID, LOCAL FRAGMENT ID */
+/* THOLD_PREV_SENT_OP NR OF SENT OPERATIONS AT */
+/* PREVIOUS SIGNALS */
+/* TLQH_POINTER LQH USER POINTER */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* LCP_HOLDOPERATION REQUEST FOR LIST OF STOPED OPERATION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execLCP_HOLDOPREQ(Signal* signal)
+{
+ Uint32 tholdPrevSentOp;
+
+ jamEntry();
+ lcpConnectptr.i = signal->theData[0]; /* CONNECTION POINTER */
+ tfid = signal->theData[1]; /* LOCAL FRAGMENT ID */
+ tholdPrevSentOp = signal->theData[2]; /* NR OF SENT OPERATIONS AT */
+ /* PREVIOUS SIGNALS */
+ tlqhPointer = signal->theData[3]; /* LQH USER POINTER */
+
+ tresult = 0;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ ndbrequire(lcpConnectptr.p->lcpstate == LCP_ACTIVE);
+ rootfragrecptr.i = lcpConnectptr.p->rootrecptr;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->fragmentid[0] == tfid) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ } else {
+ ndbrequire(rootfragrecptr.p->fragmentid[1] == tfid);
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ }//if
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->lcpLqhPtr = tlqhPointer;
+ if (tholdPrevSentOp != 0) {
+ ndbrequire(fragrecptr.p->fragState == SEND_QUE_OP);
+ } else if (tholdPrevSentOp == 0) {
+ jam();
+ fragrecptr.p->fragState = SEND_QUE_OP;
+ fragrecptr.p->stopQueOp = ZTRUE;
+ fragrecptr.p->sentWaitInQueOp = fragrecptr.p->firstWaitInQueOp;
+ }//if
+ tholdSentOp = 0; /* NR OF OPERATION WHICH ARE SENT THIS TIME */
+ operationRecPtr.i = fragrecptr.p->sentWaitInQueOp;
+
+ /* --------------------------------------------- */
+ /* GO THROUGH ALL OPERATION IN THE WAIT */
+ /* LIST AND SEND THE LQH CONNECTION PTR OF THE */
+ /* OPERATIONS TO THE LQH BLOCK. MAX 23 0PERATION */
+ /* PER SIGNAL */
+ /* --------------------------------------------- */
+ while (operationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ ckeys[tholdSentOp] = operationRecPtr.p->userptr;
+ operationRecPtr.i = operationRecPtr.p->nextQueOp;
+ tholdSentOp++;
+ if ((tholdSentOp >= 23) &&
+ (operationRecPtr.i != RNIL)) {
+ jam();
+ /* ----------------------------------------------- */
+ /* THERE IS MORE THAN 23 WAIT OPERATION. WE */
+ /* HAVE TO SEND THESE 23 AND WAITE FOR NEXT SIGNAL */
+ /* ----------------------------------------------- */
+ tholdMore = ZTRUE; /* SECOUND DATA AT THE CONF SIGNAL , = MORE */
+ fragrecptr.p->sentWaitInQueOp = operationRecPtr.i;
+ sendholdconfsignalLab(signal);
+ return;
+ }//if
+ }//while
+ /* ----------------------------------------------- */
+ /* OPERATION_REC_PTR = RNIL */
+ /* THERE IS NO MORE WAITING OPERATION, STATE OF */
+ /* THE FRAGMENT RRECORD IS CHANGED AND RETURN */
+ /* SIGNAL IS SENT */
+ /* ----------------------------------------------- */
+ fragrecptr.p->sentWaitInQueOp = RNIL;
+ tholdMore = ZFALSE; /* SECOND DATA AT THE CONF SIGNAL , = NOT MORE */
+ fragrecptr.p->fragState = WAIT_ACC_LCPREQ;
+ sendholdconfsignalLab(signal);
+ return;
+}//Dbacc::execLCP_HOLDOPREQ()
+
+void Dbacc::sendholdconfsignalLab(Signal* signal)
+{
+ tholdMore = (tholdMore << 16) + tholdSentOp;
+ /* SECOND SIGNAL DATA, LENGTH + MORE */
+ /* ************************ */
+ /* LCP_HOLDOPCONF */
+ /* ************************ */
+ signal->theData[0] = fragrecptr.p->lcpLqhPtr;
+ signal->theData[1] = tholdMore;
+ signal->theData[2] = ckeys[0];
+ signal->theData[3] = ckeys[1];
+ signal->theData[4] = ckeys[2];
+ signal->theData[5] = ckeys[3];
+ signal->theData[6] = ckeys[4];
+ signal->theData[7] = ckeys[5];
+ signal->theData[8] = ckeys[6];
+ signal->theData[9] = ckeys[7];
+ signal->theData[10] = ckeys[8];
+ signal->theData[11] = ckeys[9];
+ signal->theData[12] = ckeys[10];
+ signal->theData[13] = ckeys[11];
+ signal->theData[14] = ckeys[12];
+ signal->theData[15] = ckeys[13];
+ signal->theData[16] = ckeys[14];
+ signal->theData[17] = ckeys[15];
+ signal->theData[18] = ckeys[16];
+ signal->theData[19] = ckeys[17];
+ signal->theData[20] = ckeys[18];
+ signal->theData[21] = ckeys[19];
+ signal->theData[22] = ckeys[20];
+ signal->theData[23] = ckeys[21];
+ signal->theData[24] = ckeys[22];
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_LCP_HOLDOPCONF, signal, 25, JBA);
+ return;
+}//Dbacc::sendholdconfsignalLab()
+
+/**
+ * execACC_LCPREQ
+ * Perform local checkpoint of a fragment
+ *
+ * SENDER: LQH, LEVEL B
+ * ENTER ACC_LCPREQ WITH
+ * LCP_CONNECTPTR, OPERATION RECORD PTR
+ * TLCP_LQH_CHECK_V, LQH'S LOCAL FRAG CHECK VALUE
+ * TLCP_LOCAL_FRAG_ID, LOCAL FRAG ID
+ *
+ */
+void Dbacc::execACC_LCPREQ(Signal* signal)
+{
+ Uint32 tlcpLocalFragId;
+ Uint32 tlcpLqhCheckV;
+
+ jamEntry();
+ lcpConnectptr.i = signal->theData[0]; // CONNECTION PTR
+ tlcpLqhCheckV = signal->theData[1]; // LQH'S LOCAL FRAG CHECK VALUE
+ tlcpLocalFragId = signal->theData[2]; // LOCAL FRAG ID
+ tresult = 0;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ ndbrequire(lcpConnectptr.p->lcpstate == LCP_ACTIVE);
+
+ rootfragrecptr.i = lcpConnectptr.p->rootrecptr;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->fragmentid[0] == tlcpLocalFragId) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ } else {
+ ndbrequire(rootfragrecptr.p->fragmentid[1] == tlcpLocalFragId);
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ }//if
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ ndbrequire(fragrecptr.p->fragState == WAIT_ACC_LCPREQ);
+ fragrecptr.p->lcpLqhPtr = tlcpLqhCheckV;
+
+ Page8Ptr zeroPagePtr;
+ seizeLcpPage(zeroPagePtr);
+ fragrecptr.p->zeroPagePtr = zeroPagePtr.i;
+ fragrecptr.p->prevUndoposition = cminusOne;
+ initRootFragPageZero(rootfragrecptr, zeroPagePtr);
+ initFragPageZero(fragrecptr, zeroPagePtr);
+ /*-----------------------------------------------------------------*/
+ /* SEIZE ZERO PAGE FIRST AND THEN SEIZE DATA PAGES IN */
+ /* BACKWARDS ORDER. THIS IS TO ENSURE THAT WE GET THE PAGES */
+ /* IN ORDER. ON WINDOWS NT THIS WILL BE A BENEFIT SINCE WE */
+ /* CAN THEN DO 1 WRITE_FILE INSTEAD OF 8. */
+ /* WHEN WE RELEASE THE PAGES WE RELEASE THEM IN THE OPPOSITE */
+ /* ORDER. */
+ /*-----------------------------------------------------------------*/
+ for (Uint32 taspTmp = ZWRITEPAGESIZE - 1; (Uint32)~taspTmp; taspTmp--) {
+ Page8Ptr dataPagePtr;
+ jam();
+ ndbrequire(fragrecptr.p->datapages[taspTmp] == RNIL);
+ seizeLcpPage(dataPagePtr);
+ fragrecptr.p->datapages[taspTmp] = dataPagePtr.i;
+ }//for
+ fragrecptr.p->lcpMaxDirIndex = fragrecptr.p->dirsize;
+ fragrecptr.p->lcpMaxOverDirIndex = fragrecptr.p->lastOverIndex;
+ fragrecptr.p->createLcp = ZTRUE;
+ operationRecPtr.i = fragrecptr.p->lockOwnersList;
+ lcp_write_op_to_undolog(signal);
+}
+
+void
+Dbacc::lcp_write_op_to_undolog(Signal* signal)
+{
+ bool delay_continueb= false;
+ Uint32 i, j;
+ for (i= 0; i < 16; i++) {
+ jam();
+ if (remainingUndoPages() <= ZMIN_UNDO_PAGES_AT_COMMIT) {
+ jam();
+ delay_continueb= true;
+ break;
+ }
+ for (j= 0; j < 32; j++) {
+ if (operationRecPtr.i == RNIL) {
+ jam();
+ break;
+ }
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+
+ if ((operationRecPtr.p->operation == ZINSERT) ||
+ (operationRecPtr.p->elementIsDisappeared == ZTRUE)){
+ /*******************************************************************
+ * Only log inserts and elements that are marked as dissapeared.
+ * All other operations update the element header and that is handled
+ * when pages are written to disk
+ ********************************************************************/
+ undopageptr.i = (cundoposition>>ZUNDOPAGEINDEXBITS) & (cundopagesize-1);
+ ptrAss(undopageptr, undopage);
+ theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
+ tundoindex = theadundoindex + ZUNDOHEADSIZE;
+
+ writeUndoOpInfo(signal);/* THE INFORMATION ABOUT ELEMENT HEADER, STORED*/
+ /* IN OP REC, IS WRITTEN AT UNDO PAGES */
+ cundoElemIndex = 0;/* DEFAULT VALUE USED BY WRITE_UNDO_HEADER SUBROTINE */
+ writeUndoHeader(signal, RNIL, UndoHeader::ZOP_INFO); /* WRITE THE HEAD OF THE UNDO ELEMENT */
+ checkUndoPages(signal); /* SEND UNDO PAGE TO DISK WHEN A GROUP OF */
+ /* UNDO PAGES,CURRENTLY 8, IS FILLED */
+ }
+ operationRecPtr.i = operationRecPtr.p->nextLockOwnerOp;
+ }
+ if (operationRecPtr.i == RNIL) {
+ jam();
+ break;
+ }
+ }
+ if (operationRecPtr.i != RNIL) {
+ jam();
+ signal->theData[0]= ZLCP_OP_WRITE_RT_BREAK;
+ signal->theData[1]= operationRecPtr.i;
+ signal->theData[2]= fragrecptr.i;
+ signal->theData[3]= lcpConnectptr.i;
+ if (delay_continueb) {
+ jam();
+ sendSignalWithDelay(cownBlockref, GSN_CONTINUEB, signal, 10, 4);
+ } else {
+ jam();
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 4, JBB);
+ }
+ return;
+ }
+
+ signal->theData[0] = fragrecptr.p->lcpLqhPtr;
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_ACC_LCPSTARTED,
+ signal, 1, JBA);
+
+ fragrecptr.p->activeDataPage = 0;
+ fragrecptr.p->lcpDirIndex = 0;
+ fragrecptr.p->fragState = LCP_SEND_PAGES;
+
+ signal->theData[0] = lcpConnectptr.i;
+ signal->theData[1] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_SAVE_PAGES, signal, 2, JBB);
+}
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_SAVE_PAGES A GROUP OF PAGES IS ALLOCATED. THE PAGES AND OVERFLOW */
+/* PAGES OF THE FRAGMENT ARE COPIED IN THEM AND IS SEND TO */
+/* THE DATA FILE OF THE CHECK POINT. */
+/* SENDER: ACC, LEVEL B */
+/* ENTER ACC_SAVE_PAGES WITH */
+/* LCP_CONNECTPTR, CONNECTION RECORD PTR */
+/* FRAGRECPTR FRAGMENT RECORD PTR */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_SAVE_PAGES REQUEST TO SEND THE PAGE TO DISK */
+/* ******************------------------------------+ UNDO PAGES */
+/* SENDER: ACC, LEVEL B */
+void Dbacc::execACC_SAVE_PAGES(Signal* signal)
+{
+ jamEntry();
+ lcpConnectptr.i = signal->theData[0];
+ /* CONNECTION RECORD PTR */
+ fragrecptr.i = signal->theData[1];
+ /* FRAGMENT RECORD PTR */
+ tresult = 0;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ if (lcpConnectptr.p->lcpstate != LCP_ACTIVE) {
+ jam();
+ sendSystemerror(signal);
+ return;
+ }//if
+ if (ERROR_INSERTED(3000)) {
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->mytabptr == c_errorInsert3000_TableId){
+ ndbout << "Delay writing of datapages" << endl;
+ // Delay writing of pages
+ jam();
+ sendSignalWithDelay(cownBlockref, GSN_ACC_SAVE_PAGES, signal, 1000, 2);
+ return;
+ }
+ }
+ if (clblPageCounter == 0) {
+ jam();
+ signal->theData[0] = lcpConnectptr.i;
+ signal->theData[1] = fragrecptr.i;
+ sendSignalWithDelay(cownBlockref, GSN_ACC_SAVE_PAGES, signal, 100, 2);
+ return;
+ } else {
+ jam();
+ clblPageCounter = clblPageCounter - 1;
+ }//if
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (fragrecptr.p->fragState == LCP_SEND_PAGES) {
+ jam();
+ savepagesLab(signal);
+ return;
+ } else {
+ if (fragrecptr.p->fragState == LCP_SEND_OVER_PAGES) {
+ jam();
+ saveOverPagesLab(signal);
+ return;
+ } else {
+ ndbrequire(fragrecptr.p->fragState == LCP_SEND_ZERO_PAGE);
+ jam();
+ saveZeroPageLab(signal);
+ return;
+ }//if
+ }//if
+}//Dbacc::execACC_SAVE_PAGES()
+
+void Dbacc::savepagesLab(Signal* signal)
+{
+ DirRangePtr spDirRangePtr;
+ DirectoryarrayPtr spDirptr;
+ Page8Ptr aspPageptr;
+ Page8Ptr aspCopyPageptr;
+ Uint32 taspDirindex;
+ Uint32 taspDirIndex;
+ Uint32 taspIndex;
+
+ if ((fragrecptr.p->lcpDirIndex >= fragrecptr.p->dirsize) ||
+ (fragrecptr.p->lcpDirIndex >= fragrecptr.p->lcpMaxDirIndex)) {
+ jam();
+ endsavepageLab(signal);
+ return;
+ }//if
+ /* SOME EXPAND PROCESSES HAVE BEEN PERFORMED. */
+ /* THE ADDED PAGE ARE NOT SENT TO DISK */
+ arrGuard(fragrecptr.p->activeDataPage, 8);
+ aspCopyPageptr.i = fragrecptr.p->datapages[fragrecptr.p->activeDataPage];
+ ptrCheckGuard(aspCopyPageptr, cpagesize, page8);
+ taspDirindex = fragrecptr.p->lcpDirIndex; /* DIRECTORY OF ACTIVE PAGE */
+ spDirRangePtr.i = fragrecptr.p->directory;
+ taspDirIndex = taspDirindex >> 8;
+ taspIndex = taspDirindex & 0xff;
+ ptrCheckGuard(spDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(taspDirIndex, 256);
+ spDirptr.i = spDirRangePtr.p->dirArray[taspDirIndex];
+ ptrCheckGuard(spDirptr, cdirarraysize, directoryarray);
+ aspPageptr.i = spDirptr.p->pagep[taspIndex];
+ ptrCheckGuard(aspPageptr, cpagesize, page8);
+ ndbrequire(aspPageptr.p->word32[ZPOS_PAGE_ID] == fragrecptr.p->lcpDirIndex);
+ lcnPageptr = aspPageptr;
+ lcnCopyPageptr = aspCopyPageptr;
+ lcpCopyPage(signal);
+ fragrecptr.p->lcpDirIndex++;
+ fragrecptr.p->activeDataPage++;
+ if (fragrecptr.p->activeDataPage < ZWRITEPAGESIZE) {
+ jam();
+ signal->theData[0] = lcpConnectptr.i;
+ signal->theData[1] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_SAVE_PAGES, signal, 2, JBB);
+ return;
+ }//if
+ senddatapagesLab(signal);
+ return;
+}//Dbacc::savepagesLab()
+
+/* FRAGRECPTR:ACTIVE_DATA_PAGE = ZWRITEPAGESIZE */
+/* SEND A GROUP OF PAGES TO DISK */
+void Dbacc::senddatapagesLab(Signal* signal)
+{
+ fsConnectptr.i = fragrecptr.p->fsConnPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ seizeFsOpRec(signal);
+ initFsOpRec(signal);
+ fsOpptr.p->fsOpstate = WAIT_WRITE_DATA;
+ ndbrequire(fragrecptr.p->activeDataPage <= 8);
+ for (Uint32 i = 0; i < fragrecptr.p->activeDataPage; i++) {
+ signal->theData[i + 6] = fragrecptr.p->datapages[i];
+ }//for
+ signal->theData[fragrecptr.p->activeDataPage + 6] = fragrecptr.p->activeDataFilePage;
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsOpptr.i;
+ signal->theData[3] = 0x2;
+ signal->theData[4] = ZPAGE8_BASE_ADD;
+ signal->theData[5] = fragrecptr.p->activeDataPage;
+ sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 15, JBA);
+ return;
+}//Dbacc::senddatapagesLab()
+
+void Dbacc::endsavepageLab(Signal* signal)
+{
+ Page8Ptr espPageidptr;
+
+ espPageidptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(espPageidptr, cpagesize, page8);
+ dbgWord32(espPageidptr, ZPAGEZERO_NO_PAGES, fragrecptr.p->lcpDirIndex);
+ espPageidptr.p->word32[ZPAGEZERO_NO_PAGES] = fragrecptr.p->lcpDirIndex;
+ fragrecptr.p->fragState = LCP_SEND_OVER_PAGES;
+ fragrecptr.p->noOfStoredOverPages = 0;
+ fragrecptr.p->lcpDirIndex = 0;
+ saveOverPagesLab(signal);
+ return;
+}//Dbacc::endsavepageLab()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_SAVE_OVER_PAGES CONTINUE SAVING THE LEFT OVERPAGES. */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::saveOverPagesLab(Signal* signal)
+{
+ DirRangePtr sopDirRangePtr;
+ DirectoryarrayPtr sopOverflowDirptr;
+ Page8Ptr sopPageptr;
+ Page8Ptr sopCopyPageptr;
+ Uint32 tsopDirindex;
+ Uint32 tsopDirInd;
+ Uint32 tsopIndex;
+
+ if ((fragrecptr.p->lcpDirIndex >= fragrecptr.p->lastOverIndex) ||
+ (fragrecptr.p->lcpDirIndex >= fragrecptr.p->lcpMaxOverDirIndex)) {
+ jam();
+ endsaveoverpageLab(signal);
+ return;
+ }//if
+ arrGuard(fragrecptr.p->activeDataPage, 8);
+ sopCopyPageptr.i = fragrecptr.p->datapages[fragrecptr.p->activeDataPage];
+ ptrCheckGuard(sopCopyPageptr, cpagesize, page8);
+ tsopDirindex = fragrecptr.p->lcpDirIndex;
+ sopDirRangePtr.i = fragrecptr.p->overflowdir;
+ tsopDirInd = tsopDirindex >> 8;
+ tsopIndex = tsopDirindex & 0xff;
+ ptrCheckGuard(sopDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tsopDirInd, 256);
+ sopOverflowDirptr.i = sopDirRangePtr.p->dirArray[tsopDirInd];
+ ptrCheckGuard(sopOverflowDirptr, cdirarraysize, directoryarray);
+ sopPageptr.i = sopOverflowDirptr.p->pagep[tsopIndex];
+ fragrecptr.p->lcpDirIndex++;
+ if (sopPageptr.i != RNIL) {
+ jam();
+ ptrCheckGuard(sopPageptr, cpagesize, page8);
+ ndbrequire(sopPageptr.p->word32[ZPOS_PAGE_ID] == tsopDirindex);
+ ndbrequire(((sopPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) != ZNORMAL_PAGE_TYPE);
+ lcnPageptr = sopPageptr;
+ lcnCopyPageptr = sopCopyPageptr;
+ lcpCopyPage(signal);
+ fragrecptr.p->noOfStoredOverPages++;
+ fragrecptr.p->activeDataPage++;
+ if ((sopPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] == 0)) {
+ //ndbrequire(((sopPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZOVERFLOW_PAGE_TYPE);
+ if (((sopPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) ==
+ ZOVERFLOW_PAGE_TYPE) {
+ /*--------------------------------------------------------------------------------*/
+ /* THE PAGE IS EMPTY AND WAITING TO BE RELEASED. IT COULD NOT BE RELEASED */
+ /* EARLIER SINCE IT WAS PART OF A LOCAL CHECKPOINT. */
+ /*--------------------------------------------------------------------------------*/
+ jam();
+ ropPageptr = sopPageptr;
+ releaseOverpage(signal);
+ } else {
+ jam();
+ sendSystemerror(signal);
+ }
+ }//if
+ }
+ if (fragrecptr.p->activeDataPage == ZWRITEPAGESIZE) {
+ jam();
+ senddatapagesLab(signal);
+ return;
+ }//if
+ signal->theData[0] = lcpConnectptr.i;
+ signal->theData[1] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_SAVE_PAGES, signal, 2, JBB);
+ return;
+}//Dbacc::saveOverPagesLab()
+
+void Dbacc::endsaveoverpageLab(Signal* signal)
+{
+ Page8Ptr esoPageidptr;
+
+ esoPageidptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(esoPageidptr, cpagesize, page8);
+ dbgWord32(esoPageidptr, ZPAGEZERO_NO_OVER_PAGE, fragrecptr.p->noOfStoredOverPages);
+ esoPageidptr.p->word32[ZPAGEZERO_NO_OVER_PAGE] = fragrecptr.p->noOfStoredOverPages;
+ fragrecptr.p->fragState = LCP_SEND_ZERO_PAGE;
+ if (fragrecptr.p->activeDataPage != 0) {
+ jam();
+ senddatapagesLab(signal); /* SEND LEFT PAGES TO DISK */
+ return;
+ }//if
+ saveZeroPageLab(signal);
+ return;
+}//Dbacc::endsaveoverpageLab()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_SAVE_ZERO_PAGE PAGE ZERO IS SENT TO DISK.IT IS THE LAST STAGE AT THE */
+/* CREATION LCP. ACC_LCPCONF IS RETURND. */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::saveZeroPageLab(Signal* signal)
+{
+ Page8Ptr szpPageidptr;
+ Uint32 Tchs;
+ Uint32 Ti;
+
+ fragrecptr.p->createLcp = ZFALSE;
+ fsConnectptr.i = fragrecptr.p->fsConnPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ szpPageidptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(szpPageidptr, cpagesize, page8);
+ dbgWord32(szpPageidptr, ZPAGEZERO_PREV_UNDOP, fragrecptr.p->prevUndoposition);
+ szpPageidptr.p->word32[ZPAGEZERO_PREV_UNDOP] = fragrecptr.p->prevUndoposition;
+ dbgWord32(szpPageidptr, ZPAGEZERO_NEXT_UNDO_FILE, cactiveUndoFileVersion);
+ szpPageidptr.p->word32[ZPAGEZERO_NEXT_UNDO_FILE] = cactiveUndoFileVersion;
+ fragrecptr.p->fragState = WAIT_ZERO_PAGE_STORED;
+
+ /* --------------------------------------------------------------------------------- */
+ // Calculate the checksum and store it for the zero page of the fragment.
+ /* --------------------------------------------------------------------------------- */
+ szpPageidptr.p->word32[ZPOS_CHECKSUM] = 0;
+ Tchs = 0;
+ for (Ti = 0; Ti < 2048; Ti++) {
+ Tchs = Tchs ^ szpPageidptr.p->word32[Ti];
+ }//for
+ szpPageidptr.p->word32[ZPOS_CHECKSUM] = Tchs;
+ dbgWord32(szpPageidptr, ZPOS_CHECKSUM, Tchs);
+
+ seizeFsOpRec(signal);
+ initFsOpRec(signal);
+ fsOpptr.p->fsOpstate = WAIT_WRITE_DATA;
+ if (clblPageCounter > 0) {
+ jam();
+ clblPageCounter = clblPageCounter - 1;
+ } else {
+ jam();
+ clblPageOver = clblPageOver + 1;
+ }//if
+ /* ************************ */
+ /* FSWRITEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsOpptr.i;
+ signal->theData[3] = 0x10;
+ /* FLAG = LIST MEM PAGES, LIST FILE PAGES */
+ /* SYNC FILE AFTER WRITING */
+ signal->theData[4] = ZPAGE8_BASE_ADD;
+ signal->theData[5] = 1;
+ /* NO OF PAGES */
+ signal->theData[6] = fragrecptr.p->zeroPagePtr;
+ /* ZERO PAGE */
+ signal->theData[7] = 0;
+ sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
+ /* ZERO PAGE AT DATA FILE */
+ return;
+}//Dbacc::saveZeroPageLab()
+
+/* ******************--------------------------------------------------------------- */
+/* FSWRITECONF OPENFILE CONF */
+/* ENTER FSWRITECONF WITH SENDER: FS, LEVEL B */
+/* FS_OPPTR FS_CONNECTION PTR */
+/* ******************--------------------------------------------------------------- */
+void Dbacc::lcpCloseDataFileLab(Signal* signal)
+{
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ fsConnectptr.p->fsState = LCP_CLOSE_DATA;
+ /* ************************ */
+ /* FSCLOSEREQ */
+ /* ************************ */
+ /* CLOSE DATA FILE */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = ZFALSE;
+ sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA);
+ /* FLAG = 0, DO NOT DELETE FILE */
+ return;
+}//Dbacc::lcpCloseDataFileLab()
+
+void Dbacc::checkSyncUndoPagesLab(Signal* signal)
+{
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ releaseFsConnRec(signal);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ switch (lcpConnectptr.p->syncUndopageState) {
+ case WAIT_NOTHING:
+ jam();
+ lcpConnectptr.p->syncUndopageState = WAIT_ONE_CONF;
+ break;
+ case WAIT_ONE_CONF:
+ jam();
+ lcpConnectptr.p->syncUndopageState = WAIT_TWO_CONF;
+ break;
+ default:
+ jam();
+ sendSystemerror(signal);
+ return;
+ break;
+ }//switch
+
+ /* ACTIVE UNDO PAGE ID */
+ Uint32 tundoPageId = cundoposition >> ZUNDOPAGEINDEXBITS;
+ tmp1 = tundoPageId - (tundoPageId & (ZWRITE_UNDOPAGESIZE - 1));
+ /* START PAGE OF THE LAST UNDO PAGES GROUP */
+ tmp2 = (tundoPageId - tmp1) + 1; /* NO OF LEFT UNDO PAGES */
+ tmp1 = tmp1 & (cundopagesize - 1); /* 1 MBYTE PAGE WINDOW IN MEMORY */
+ fsConnectptr.i = cactiveOpenUndoFsPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ seizeFsOpRec(signal);
+ initFsOpRec(signal);
+ fsOpptr.p->fsOpstate = WAIT_WRITE_UNDO;
+ fsOpptr.p->fsOpMemPage = tundoPageId; /* RECORD MEMORY PAGE WRITTEN */
+ if (clblPageCounter >= (4 * tmp2)) {
+ jam();
+ clblPageCounter = clblPageCounter - (4 * tmp2);
+ } else {
+ jam();
+ clblPageOver = clblPageOver + ((4 * tmp2) - clblPageCounter);
+ clblPageCounter = 0;
+ }//if
+ /* ************************ */
+ /* FSWRITEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsOpptr.i;
+ /* FLAG = START MEM PAGES, START FILE PAGES */
+ /* SYNC FILE AFTER WRITING */
+ signal->theData[3] = 0x11;
+ signal->theData[4] = ZUNDOPAGE_BASE_ADD;
+ /* NO OF UNDO PAGES */
+ signal->theData[5] = tmp2;
+ /* FIRST MEMORY PAGE */
+ signal->theData[6] = tmp1;
+ /* ACTIVE PAGE AT UNDO FILE */
+ signal->theData[7] = cactiveUndoFilePage;
+ sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
+
+ return;
+}//Dbacc::checkSyncUndoPagesLab()
+
+void Dbacc::checkSendLcpConfLab(Signal* signal)
+{
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ ndbrequire(lcpConnectptr.p->lcpstate == LCP_ACTIVE);
+ switch (lcpConnectptr.p->syncUndopageState) {
+ case WAIT_ONE_CONF:
+ jam();
+ lcpConnectptr.p->syncUndopageState = WAIT_NOTHING;
+ break;
+ case WAIT_TWO_CONF:
+ jam();
+ lcpConnectptr.p->syncUndopageState = WAIT_ONE_CONF;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ lcpConnectptr.p->noOfLcpConf++;
+ ndbrequire(lcpConnectptr.p->noOfLcpConf <= 2);
+ fragrecptr.p->fragState = ACTIVEFRAG;
+ rlpPageptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(rlpPageptr, cpagesize, page8);
+ releaseLcpPage(signal);
+ fragrecptr.p->zeroPagePtr = RNIL;
+ for (Uint32 i = 0; i < ZWRITEPAGESIZE; i++) {
+ jam();
+ if (fragrecptr.p->datapages[i] != RNIL) {
+ jam();
+ rlpPageptr.i = fragrecptr.p->datapages[i];
+ ptrCheckGuard(rlpPageptr, cpagesize, page8);
+ releaseLcpPage(signal);
+ fragrecptr.p->datapages[i] = RNIL;
+ }//if
+ }//for
+ signal->theData[0] = fragrecptr.p->lcpLqhPtr;
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_ACC_LCPCONF, signal, 1, JBB);
+ if (lcpConnectptr.p->noOfLcpConf == 2) {
+ jam();
+ releaseLcpConnectRec(signal);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ rootfragrecptr.p->rootState = ACTIVEROOT;
+ }//if
+}//Dbacc::checkSendLcpConfLab()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_CONTOPREQ */
+/* SENDER: LQH, LEVEL B */
+/* ENTER ACC_CONTOPREQ WITH */
+/* LCP_CONNECTPTR */
+/* TMP1 LOCAL FRAG ID */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_CONTOPREQ COMMIT TRANSACTION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACC_CONTOPREQ(Signal* signal)
+{
+ Uint32 tcorLocalFrag;
+
+ jamEntry();
+ lcpConnectptr.i = signal->theData[0];
+ /* CONNECTION PTR */
+ tcorLocalFrag = signal->theData[1];
+ /* LOCAL FRAG ID */
+ tresult = 0;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ ndbrequire(lcpConnectptr.p->lcpstate == LCP_ACTIVE);
+ rootfragrecptr.i = lcpConnectptr.p->rootrecptr;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->fragmentid[0] == tcorLocalFrag) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ } else {
+ ndbrequire(rootfragrecptr.p->fragmentid[1] == tcorLocalFrag);
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ }//if
+ operationRecPtr.i = fragrecptr.p->firstWaitInQueOp;
+ fragrecptr.p->sentWaitInQueOp = RNIL;
+ fragrecptr.p->stopQueOp = ZFALSE;
+ while (operationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ if (operationRecPtr.p->opState == WAIT_EXE_OP) {
+ jam();
+ //------------------------------------------------------------
+ // Indicate that we are now a normal waiter in the queue. We
+ // will remove the operation from the queue as part of starting
+ // operation again.
+ //------------------------------------------------------------
+ operationRecPtr.p->opState = WAIT_IN_QUEUE;
+ executeNextOperation(signal);
+ }//if
+ operationRecPtr.i = operationRecPtr.p->nextQueOp;
+ }//while
+ signal->theData[0] = fragrecptr.p->lcpLqhPtr;
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_ACC_CONTOPCONF, signal, 1, JBA);
+ return; /* ALL QUEUED OPERATION ARE RESTARTED IF NEEDED. */
+}//Dbacc::execACC_CONTOPREQ()
+
+/* ******************--------------------------------------------------------------- */
+/* END_LCPREQ END OF LOCAL CHECK POINT */
+/* ENTER END_LCPREQ WITH SENDER: LQH, LEVEL B */
+/* CLQH_PTR, LQH PTR */
+/* CLQH_BLOCK_REF LQH BLOCK REF */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* END_LCPREQ PERFORM A LOCAL CHECK POINT */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execEND_LCPREQ(Signal* signal)
+{
+ jamEntry();
+ clqhPtr = signal->theData[0];
+ /* LQH PTR */
+ clqhBlockRef = signal->theData[1];
+ /* LQH BLOCK REF */
+ tresult = 0;
+ fsConnectptr.i = cactiveOpenUndoFsPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ fsConnectptr.p->fsState = WAIT_CLOSE_UNDO; /* CLOSE FILE AFTER WRITTING */
+ /* ************************ */
+ /* FSCLOSEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = ZFALSE;
+ sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA);
+ /* FLAG = 0, DO NOT DELETE FILE */
+ cactiveUndoFileVersion = RNIL;
+ cactiveOpenUndoFsPtr = RNIL;
+ /* ************************ */
+ /* END_LCPCONF */
+ /* ************************ */
+ signal->theData[0] = clqhPtr;
+ sendSignal(clqhBlockRef, GSN_END_LCPCONF, signal, 1, JBB);
+ return;
+}//Dbacc::execEND_LCPREQ()
+
+/*-----------------------------------------------------------------*/
+/* WHEN WE COPY THE PAGE WE ALSO WRITE THE ELEMENT HEADER AS */
+/* UNLOCKED IF THEY ARE CURRENTLY LOCKED. */
+/*-----------------------------------------------------------------*/
+void Dbacc::lcpCopyPage(Signal* signal)
+{
+ Uint32 tlcnNextContainer;
+ Uint32 tlcnTmp;
+ Uint32 tlcnConIndex;
+ Uint32 tlcnIndex;
+ Uint32 Tmp1;
+ Uint32 Tmp2;
+ Uint32 Tmp3;
+ Uint32 Tmp4;
+ Uint32 Ti;
+ Uint32 Tchs;
+ Uint32 Tlimit;
+
+ Tchs = 0;
+ lupPageptr.p = lcnCopyPageptr.p;
+ lcnPageptr.p->word32[ZPOS_CHECKSUM] = Tchs;
+ for (Ti = 0; Ti < 32 ; Ti++) {
+ Tlimit = 16 + (Ti << 6);
+ for (tlcnTmp = (Ti << 6); tlcnTmp < Tlimit; tlcnTmp ++) {
+ Tmp1 = lcnPageptr.p->word32[tlcnTmp];
+ Tmp2 = lcnPageptr.p->word32[tlcnTmp + 16];
+ Tmp3 = lcnPageptr.p->word32[tlcnTmp + 32];
+ Tmp4 = lcnPageptr.p->word32[tlcnTmp + 48];
+
+ lcnCopyPageptr.p->word32[tlcnTmp] = Tmp1;
+ lcnCopyPageptr.p->word32[tlcnTmp + 16] = Tmp2;
+ lcnCopyPageptr.p->word32[tlcnTmp + 32] = Tmp3;
+ lcnCopyPageptr.p->word32[tlcnTmp + 48] = Tmp4;
+
+ Tchs = Tchs ^ Tmp1;
+ Tchs = Tchs ^ Tmp2;
+ Tchs = Tchs ^ Tmp3;
+ Tchs = Tchs ^ Tmp4;
+ }//for
+ }//for
+ tlcnChecksum = Tchs;
+ if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
+ jam();
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
+ /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
+ /* HEADER OF 2 WORDS. */
+ /*-----------------------------------------------------------------*/
+ tlcnConIndex = ZHEAD_SIZE;
+ tlupForward = 1;
+ for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ lcpUpdatePage(signal);
+ tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
+ }//for
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ tlupForward = 1;
+ lcpUpdatePage(signal);
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ sendSystemerror(signal);
+ return;
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlupForward = cminusOne;
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex - 1;
+ lcpUpdatePage(signal);
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ sendSystemerror(signal);
+ return;
+ }//if
+ lcnCopyPageptr.p->word32[ZPOS_CHECKSUM] = tlcnChecksum;
+}//Dbacc::lcpCopyPage()
+
+/* --------------------------------------------------------------------------------- */
+/* THIS SUBROUTINE GOES THROUGH ONE CONTAINER TO CHECK FOR LOCKED ELEMENTS AND */
+/* UPDATING THEM TO ENSURE ALL ELEMENTS ARE UNLOCKED ON DISK. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::lcpUpdatePage(Signal* signal)
+{
+ OperationrecPtr lupOperationRecPtr;
+ Uint32 tlupElemHead;
+ Uint32 tlupElemLen;
+ Uint32 tlupElemStep;
+ Uint32 tlupConLen;
+
+ tlupConLen = lupPageptr.p->word32[tlupIndex] >> 26;
+ tlupElemLen = fragrecptr.p->elementLength;
+ tlupElemStep = tlupForward * tlupElemLen;
+ while (tlupConLen > ZCON_HEAD_SIZE) {
+ jam();
+ tlupElemHead = lupPageptr.p->word32[tlupElemIndex];
+ if (ElementHeader::getLocked(tlupElemHead)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* WHEN CHANGING THE ELEMENT HEADER WE ALSO HAVE TO UPDATE THE CHECKSUM. IN */
+ /* DOING THIS WE USE THE FORMULA (A XOR B) XOR B = A WHICH MEANS THAT IF WE */
+ /* XOR SOMETHING TWICE WITH THE SAME OPERAND THEN WE RETURN TO THE ORIGINAL */
+ /* VALUE. THEN WE ALSO HAVE TO USE THE NEW ELEMENT HEADER IN THE CHECKSUM */
+ /* CALCULATION. */
+ /* --------------------------------------------------------------------------------- */
+ tlcnChecksum = tlcnChecksum ^ tlupElemHead;
+ lupOperationRecPtr.i = ElementHeader::getOpPtrI(tlupElemHead);
+ ptrCheckGuard(lupOperationRecPtr, coprecsize, operationrec);
+ const Uint32 hv = lupOperationRecPtr.p->hashvaluePart;
+ tlupElemHead = ElementHeader::setUnlocked(hv , 0);
+ arrGuard(tlupElemIndex, 2048);
+ lupPageptr.p->word32[tlupElemIndex] = tlupElemHead;
+ tlcnChecksum = tlcnChecksum ^ tlupElemHead;
+ }//if
+ tlupConLen = tlupConLen - tlupElemLen;
+ tlupElemIndex = tlupElemIndex + tlupElemStep;
+ }//while
+ if (tlupConLen < ZCON_HEAD_SIZE) {
+ jam();
+ sendSystemerror(signal);
+ }//if
+}//Dbacc::lcpUpdatePage()
+
+/*-----------------------------------------------------------------*/
+// At a system restart we check that the page do not contain any
+// locks that hinder the system restart procedure.
+/*-----------------------------------------------------------------*/
+void Dbacc::srCheckPage(Signal* signal)
+{
+ Uint32 tlcnNextContainer;
+ Uint32 tlcnConIndex;
+ Uint32 tlcnIndex;
+
+ lupPageptr.p = lcnCopyPageptr.p;
+ if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
+ jam();
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
+ /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
+ /* HEADER OF 2 WORDS. */
+ /*-----------------------------------------------------------------*/
+ tlcnConIndex = ZHEAD_SIZE;
+ tlupForward = 1;
+ for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ srCheckContainer(signal);
+ if (tresult != 0) {
+ jam();
+ return;
+ }//if
+ tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
+ }//for
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ tlupForward = 1;
+ srCheckContainer(signal);
+ if (tresult != 0) {
+ jam();
+ return;
+ }//if
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ tresult = 4;
+ return;
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlupForward = cminusOne;
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex - 1;
+ srCheckContainer(signal);
+ if (tresult != 0) {
+ jam();
+ return;
+ }//if
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ tresult = 4;
+ return;
+ }//if
+}//Dbacc::srCheckPage()
+
+/* --------------------------------------------------------------------------------- */
+/* THIS SUBROUTINE GOES THROUGH ONE CONTAINER TO CHECK FOR LOCKED ELEMENTS AND */
+/* UPDATING THEM TO ENSURE ALL ELEMENTS ARE UNLOCKED ON DISK. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::srCheckContainer(Signal* signal)
+{
+ Uint32 tlupElemLen;
+ Uint32 tlupElemStep;
+ Uint32 tlupConLen;
+
+ tlupConLen = lupPageptr.p->word32[tlupIndex] >> 26;
+ tlupElemLen = fragrecptr.p->elementLength;
+ tlupElemStep = tlupForward * tlupElemLen;
+ while (tlupConLen > ZCON_HEAD_SIZE) {
+ jam();
+ const Uint32 tlupElemHead = lupPageptr.p->word32[tlupElemIndex];
+ if (ElementHeader::getLocked(tlupElemHead)){
+ jam();
+ //-------------------------------------------------------
+ // This is absolutely undesirable. We have a lock remaining
+ // after the system restart. We send a crash signal that will
+ // enter the trace file.
+ //-------------------------------------------------------
+ tresult = 2;
+ return;
+ }//if
+ tlupConLen = tlupConLen - tlupElemLen;
+ tlupElemIndex = tlupElemIndex + tlupElemStep;
+ }//while
+ if (tlupConLen < ZCON_HEAD_SIZE) {
+ jam();
+ tresult = 3;
+ }//if
+ return;
+}//Dbacc::srCheckContainer()
+
+/* ------------------------------------------------------------------------- */
+/* CHECK_UNDO_PAGES */
+/* DESCRIPTION: CHECKS WHEN A PAGE OR A GROUP OF UNDO PAGES IS FILLED.WHEN */
+/* A PAGE IS FILLED, CUNDOPOSITION WILL BE UPDATE, THE NEW */
+/* POSITION IS THE BEGNING OF THE NEXT UNDO PAGE. */
+/* IN CASE THAT A GROUP IS FILLED THE PAGES ARE SENT TO DISK, */
+/* AND A NEW GROUP IS CHOSEN. */
+/* ------------------------------------------------------------------------- */
+void Dbacc::checkUndoPages(Signal* signal)
+{
+
+ fragrecptr.p->prevUndoposition = cundoposition;
+ cprevUndoaddress = cundoposition;
+
+ // Calculate active undo page id
+ Uint32 tundoPageId = cundoposition >> ZUNDOPAGEINDEXBITS;
+
+ /**
+ * WE WILL WRITE UNTIL WE HAVE ABOUT 8 KBYTE REMAINING ON THE 32 KBYTE
+ * PAGE. THIS IS TO ENSURE THAT WE DO NOT HAVE ANY UNDO LOG RECORDS THAT PASS
+ * A PAGE BOUNDARIE. THIS SIMPLIFIES CODING TRADING SOME INEFFICIENCY.
+ */
+ static const Uint32 ZMAXUNDOPAGEINDEX = 7100;
+ if (tundoindex < ZMAXUNDOPAGEINDEX) {
+ jam();
+ cundoposition = (tundoPageId << ZUNDOPAGEINDEXBITS) + tundoindex;
+ return;
+ }//if
+
+ /**
+ * WE CHECK IF MORE THAN 1 MBYTE OF WRITES ARE OUTSTANDING TO THE UNDO FILE.
+ * IF SO WE HAVE TO CRASH SINCE WE HAVE NO MORE SPACE TO WRITE UNDO LOG
+ * RECORDS IN
+ */
+ Uint16 nextUndoPageId = tundoPageId + 1;
+ updateUndoPositionPage(signal, nextUndoPageId << ZUNDOPAGEINDEXBITS);
+
+ if ((tundoPageId & (ZWRITE_UNDOPAGESIZE - 1)) == (ZWRITE_UNDOPAGESIZE - 1)) {
+ jam();
+ /* ---------- SEND A GROUP OF UNDO PAGES TO DISK --------- */
+ fsConnectptr.i = cactiveOpenUndoFsPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ Uint32 tcupTmp1 = (tundoPageId - ZWRITE_UNDOPAGESIZE) + 1;
+ tcupTmp1 = tcupTmp1 & (cundopagesize - 1); /* 1 MBYTE PAGE WINDOW */
+ seizeFsOpRec(signal);
+ initFsOpRec(signal);
+ fsOpptr.p->fsOpstate = WAIT_WRITE_UNDO_EXIT;
+ fsOpptr.p->fsOpMemPage = tundoPageId;
+ fragrecptr.p->nrWaitWriteUndoExit++;
+ if (clblPageCounter >= 8) {
+ jam();
+ clblPageCounter = clblPageCounter - 8;
+ } else {
+ jam();
+ clblPageOver = clblPageOver + (8 - clblPageCounter);
+ clblPageCounter = 0;
+ }//if
+ /* ************************ */
+ /* FSWRITEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsOpptr.i;
+ signal->theData[3] = 0x1;
+ /* FLAG = START MEM PAGES, START FILE PAGES */
+ signal->theData[4] = ZUNDOPAGE_BASE_ADD;
+ signal->theData[5] = ZWRITE_UNDOPAGESIZE;
+ signal->theData[6] = tcupTmp1;
+ signal->theData[7] = cactiveUndoFilePage;
+ sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
+ cactiveUndoFilePage = cactiveUndoFilePage + ZWRITE_UNDOPAGESIZE;
+ }//if
+}//Dbacc::checkUndoPages()
+
+/* --------------------------------------------------------------------------------- */
+/* UNDO_WRITING_PROCESS */
+/* INPUT: FRAGRECPTR, CUNDO_ELEM_INDEX, DATAPAGEPTR, CUNDOINFOLENGTH */
+/* DESCRIPTION: WHEN THE PROCESS OF CREATION LOCAL CHECK POINT HAS */
+/* STARTED. IF THE ACTIVE PAGE IS NOT ALREADY SENT TO DISK, THE */
+/* OLD VALUE OF THE ITEM WHICH IS GOING TO BE CHECKED IS STORED ON */
+/* THE ACTIVE UNDO PAGE. INFORMATION ABOUT UNDO PROCESS IN THE */
+/* BLOCK AND IN THE FRAGMENT WILL BE UPDATED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::undoWritingProcess(Signal* signal)
+{
+ const Uint32 tactivePageDir = datapageptr.p->word32[ZPOS_PAGE_ID];
+ const Uint32 tpageType = (datapageptr.p->word32[ZPOS_EMPTY_LIST] >> ZPOS_PAGE_TYPE_BIT) & 3;
+ if (fragrecptr.p->fragState == LCP_SEND_PAGES) {
+ if (tpageType == ZNORMAL_PAGE_TYPE) {
+ /* --------------------------------------------------------------------------- */
+ /* HANDLING OF LOG OF NORMAL PAGES DURING WRITE OF NORMAL PAGES. */
+ /* --------------------------------------------------------------------------- */
+ if (tactivePageDir < fragrecptr.p->lcpDirIndex) {
+ jam();
+ /* ------------------------------------------------------------------- */
+ /* THIS PAGE HAS ALREADY BEEN WRITTEN IN THE LOCAL CHECKPOINT. */
+ /* ------------------------------------------------------------------- */
+ /*empty*/;
+ } else {
+ if (tactivePageDir >= fragrecptr.p->lcpMaxDirIndex) {
+ jam();
+ /* --------------------------------------------------------------------------- */
+ /* OBVIOUSLY THE FRAGMENT HAS EXPANDED SINCE THE START OF THE LOCAL CHECKPOINT.*/
+ /* WE NEED NOT LOG ANY UPDATES OF PAGES THAT DID NOT EXIST AT START OF LCP. */
+ /* --------------------------------------------------------------------------- */
+ /*empty*/;
+ } else {
+ jam();
+ /* --------------------------------------------------------------------------- */
+ /* IN ALL OTHER CASES WE HAVE TO WRITE TO THE UNDO LOG. */
+ /* --------------------------------------------------------------------------- */
+ undopageptr.i = (cundoposition >> ZUNDOPAGEINDEXBITS) & (cundopagesize - 1);
+ ptrAss(undopageptr, undopage);
+ theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
+ tundoindex = theadundoindex + ZUNDOHEADSIZE;
+ writeUndoHeader(signal, tactivePageDir, UndoHeader::ZPAGE_INFO);
+ tundoElemIndex = cundoElemIndex;
+ writeUndoDataInfo(signal);
+ checkUndoPages(signal);
+ }//if
+ }//if
+ } else if (tpageType == ZOVERFLOW_PAGE_TYPE) {
+ /* --------------------------------------------------------------------------------- */
+ /* OVERFLOW PAGE HANDLING DURING WRITE OF NORMAL PAGES. */
+ /* --------------------------------------------------------------------------------- */
+ if (tactivePageDir >= fragrecptr.p->lcpMaxOverDirIndex) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* OBVIOUSLY THE FRAGMENT HAS EXPANDED THE NUMBER OF OVERFLOW PAGES SINCE THE */
+ /* START OF THE LOCAL CHECKPOINT. WE NEED NOT LOG ANY UPDATES OF PAGES THAT DID*/
+ /* NOT EXIST AT START OF LCP. */
+ /* --------------------------------------------------------------------------------- */
+ /*empty*/;
+ } else {
+ jam();
+ undopageptr.i = (cundoposition >> ZUNDOPAGEINDEXBITS) & (cundopagesize - 1);
+ ptrAss(undopageptr, undopage);
+ theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
+ tundoindex = theadundoindex + ZUNDOHEADSIZE;
+ writeUndoHeader(signal, tactivePageDir, UndoHeader::ZOVER_PAGE_INFO);
+ tundoElemIndex = cundoElemIndex;
+ writeUndoDataInfo(signal);
+ checkUndoPages(signal);
+ }//if
+ } else {
+ jam();
+ /* --------------------------------------------------------------------------- */
+ /* ONLY PAGE INFO AND OVERFLOW PAGE INFO CAN BE LOGGED BY THIS ROUTINE. A */
+ /* SERIOUS ERROR. */
+ /* --------------------------------------------------------------------------- */
+ sendSystemerror(signal);
+ }
+ } else {
+ if (fragrecptr.p->fragState == LCP_SEND_OVER_PAGES) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* DURING WRITE OF OVERFLOW PAGES WE NEED NOT WORRY ANYMORE ABOUT NORMAL PAGES.*/
+ /* --------------------------------------------------------------------------------- */
+ if (tpageType == ZOVERFLOW_PAGE_TYPE) {
+ if (tactivePageDir < fragrecptr.p->lcpDirIndex) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THIS PAGE HAS ALREADY BEEN WRITTEN IN THE LOCAL CHECKPOINT. */
+ /* --------------------------------------------------------------------------------- */
+ /*empty*/;
+ } else {
+ if (tactivePageDir >= fragrecptr.p->lcpMaxOverDirIndex) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* OBVIOUSLY THE FRAGMENT HAS EXPANDED THE NUMBER OF OVERFLOW PAGES SINCE THE */
+ /* START OF THE LOCAL CHECKPOINT. WE NEED NOT LOG ANY UPDATES OF PAGES THAT DID*/
+ /* NOT EXIST AT START OF LCP. */
+ /* --------------------------------------------------------------------------------- */
+ /*empty*/;
+ } else {
+ jam();
+ undopageptr.i = (cundoposition >> ZUNDOPAGEINDEXBITS) & (cundopagesize - 1);
+ ptrAss(undopageptr, undopage);
+ theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
+ tundoindex = theadundoindex + ZUNDOHEADSIZE;
+ writeUndoHeader(signal, tactivePageDir, UndoHeader::ZOVER_PAGE_INFO);
+ tundoElemIndex = cundoElemIndex;
+ writeUndoDataInfo(signal);
+ checkUndoPages(signal);
+ }//if
+ }//if
+ }
+ }//if
+ }//if
+}//Dbacc::undoWritingProcess()
+
+/* --------------------------------------------------------------------------------- */
+/* OTHER STATES MEANS THAT WE HAVE ALREADY WRITTEN ALL PAGES BUT NOT YET RESET */
+/* THE CREATE_LCP FLAG. */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* WRITE_UNDO_DATA_INFO */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::writeUndoDataInfo(Signal* signal)
+{
+ Uint32 twudiIndex;
+ Uint32 guard22;
+
+ guard22 = cundoinfolength;
+ arrGuard((tundoindex + guard22 - 1), 8192);
+ arrGuard((tundoElemIndex + guard22 - 1), 2048);
+ for (twudiIndex = 1; twudiIndex <= guard22; twudiIndex++) {
+ undopageptr.p->undoword[tundoindex] = datapageptr.p->word32[tundoElemIndex];
+ tundoindex++;
+ tundoElemIndex++;
+ }//for
+}//Dbacc::writeUndoDataInfo()
+
+/* --------------------------------------------------------------------------------- */
+/* WRITE_UNDO_HEADER */
+/* THE HEAD OF UNDO ELEMENT IS 24 BYTES AND CONTAINS THE FOLLOWING INFORMATION: */
+/* TABLE IDENTITY 32 BITS */
+/* ROOT FRAGMENT IDENTITY 32 BITS */
+/* LOCAL FRAGMENT IDENTITY 32 BITS */
+/* LENGTH OF ELEMENT INF0 (BIT 31 - 18) 14 BITS */
+/* INFO TYPE (BIT 17 - 14) 4 BITS */
+/* PAGE INDEX OF THE FIRST FIELD IN THE FRAGMENT (BIT 13 - 0) 14 BITS */
+/* DIRECTORY INDEX OF THE PAGE IN THE FRAGMENT 32 BITS */
+/* ADDRESS OF THE PREVIOUS ELEMENT OF THE FRAGMENT 64 BITS */
+/* ADDRESS OF THE PREVIOUS ELEMENT IN THE UNDO PAGES 64 BITS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::writeUndoHeader(Signal* signal,
+ Uint32 logicalPageId,
+ UndoHeader::UndoHeaderType pageType)
+{
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ arrGuard(theadundoindex + 6, 8192);
+
+ // Set the structpointer to point at the undo page at the right address.
+ UndoHeader * const & undoHeaderPtr =
+ (UndoHeader *) &undopageptr.p->undoword[theadundoindex];
+
+ undoHeaderPtr->tableId = rootfragrecptr.p->mytabptr;
+ undoHeaderPtr->rootFragId = rootfragrecptr.p->fragmentid[0] >> 1;
+ undoHeaderPtr->localFragId = fragrecptr.p->myfid;
+ ndbrequire((undoHeaderPtr->localFragId >> 1) == undoHeaderPtr->rootFragId);
+ Uint32 Ttmp = cundoinfolength;
+ Ttmp = (Ttmp << 4) + pageType;
+ Ttmp = Ttmp << 14;
+ undoHeaderPtr->variousInfo = Ttmp + cundoElemIndex;
+ undoHeaderPtr->logicalPageId = logicalPageId;
+ undoHeaderPtr->prevUndoAddressForThisFrag = fragrecptr.p->prevUndoposition;
+ undoHeaderPtr->prevUndoAddress = cprevUndoaddress;
+}//Dbacc::writeUndoHeader()
+
+/* --------------------------------------------------------------------------------- */
+/* WRITE_UNDO_OP_INFO */
+/* FOR A LOCKED ELEMENT, OPERATION TYPE, UNDO OF ELEMENT HEADER AND THE LENGTH OF*/
+/* THE TUPLE KEY HAVE TO BE SAVED IN UNDO PAGES. IN THIS CASE AN UNDO ELEMENT */
+/* INCLUDES THE FLLOWING ITEMS. */
+/* OPERATION TYPE 32 BITS */
+/* HASH VALUE 32 BITS */
+/* LENGTH OF THE TUPLE = N 32 BITS */
+/* TUPLE KEYS N * 32 BITS */
+/* */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::writeUndoOpInfo(Signal* signal)
+{
+ Page8Ptr locPageptr;
+
+ arrGuard((tundoindex + 3), 8192);
+ undopageptr.p->undoword[tundoindex] = operationRecPtr.p->operation;
+ undopageptr.p->undoword[tundoindex + 1] = operationRecPtr.p->hashValue;
+ undopageptr.p->undoword[tundoindex + 2] = operationRecPtr.p->tupkeylen;
+ tundoindex = tundoindex + 3;
+ // log localkey1
+ locPageptr.i = operationRecPtr.p->elementPage;
+ ptrCheckGuard(locPageptr, cpagesize, page8);
+ Uint32 Tforward = operationRecPtr.p->elementIsforward;
+ Uint32 TelemPtr = operationRecPtr.p->elementPointer;
+ TelemPtr += Tforward; // ZELEM_HEAD_SIZE
+ arrGuard(tundoindex+1, 8192);
+ undopageptr.p->undoword[tundoindex] = locPageptr.p->word32[TelemPtr];
+ tundoindex++;
+ cundoinfolength = ZOP_HEAD_INFO_LN + 1;
+}//Dbacc::writeUndoOpInfo()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF LOCAL CHECKPOINT MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* SYSTEM RESTART MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* SR_FRAGIDREQ REQUEST FOR RESTART OF A FRAGMENT */
+/* SENDER: LQH, LEVEL B */
+/* ENTER SR_FRAGIDREQ WITH */
+/* TUSERPTR, LQH CONNECTION PTR */
+/* TUSERBLOCKREF, LQH BLOCK REFERENCE */
+/* TCHECKPOINTID, THE CHECKPOINT NUMBER TO USE */
+/* (E.G. 1,2 OR 3) */
+/* TABPTR, TABLE ID = TABLE RECORD POINTER */
+/* TFID, ROOT FRAGMENT ID */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* SR_FRAGIDREQ REQUEST FOR LIST OF STOPED OPERATION */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execSR_FRAGIDREQ(Signal* signal)
+{
+ jamEntry();
+ tuserptr = signal->theData[0]; /* LQH CONNECTION PTR */
+ tuserblockref = signal->theData[1]; /* LQH BLOCK REFERENCE */
+ tcheckpointid = signal->theData[2]; /* THE CHECKPOINT NUMBER TO USE */
+ /* (E.G. 1,2 OR 3) */
+ tabptr.i = signal->theData[3];
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ /* TABLE ID = TABLE RECORD POINTER */
+ tfid = signal->theData[4]; /* ROOT FRAGMENT ID */
+ tresult = 0; /* 0= FALSE,1= TRUE,> ZLIMIT_OF_ERROR =ERRORCODE */
+ seizeLcpConnectRec(signal);
+ initLcpConnRec(signal);
+
+ ndbrequire(getrootfragmentrec(signal, rootfragrecptr, tfid));
+ rootfragrecptr.p->lcpPtr = lcpConnectptr.i;
+ lcpConnectptr.p->rootrecptr = rootfragrecptr.i;
+ lcpConnectptr.p->localCheckPid = tcheckpointid;
+ for (Uint32 i = 0; i < 2; i++) {
+ Page8Ptr zeroPagePtr;
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[i];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ seizeLcpPage(zeroPagePtr);
+ fragrecptr.p->zeroPagePtr = zeroPagePtr.i;
+ }//for
+
+ /* ---------------------------OPEN THE DATA FILE WHICH BELONGS TO TFID AND TCHECK POINT ---- */
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ tfid = rootfragrecptr.p->fragmentid[0];
+ tmp = 0;
+ srOpenDataFileLoopLab(signal);
+
+ return;
+}//Dbacc::execSR_FRAGIDREQ()
+
+void Dbacc::srOpenDataFileLoopLab(Signal* signal)
+{
+ /* D6 AT FSOPENREQ. FILE TYPE = .DATA */
+ tmp1 = 0x010003ff; /* VERSION OF FILENAME = 1 */
+ tmp2 = 0x0; /* D7 DON'T CREATE, READ ONLY */
+ ndbrequire(cfsFirstfreeconnect != RNIL);
+ seizeFsConnectRec(signal);
+
+ fragrecptr.p->fsConnPtr = fsConnectptr.i;
+ fsConnectptr.p->fragrecPtr = fragrecptr.i;
+ fsConnectptr.p->fsState = WAIT_OPEN_DATA_FILE_FOR_READ;
+ fsConnectptr.p->activeFragId = tmp; /* LOCAL FRAG INDEX */
+ /* ************************ */
+ /* FSOPENREQ */
+ /* ************************ */
+ signal->theData[0] = cownBlockref;
+ signal->theData[1] = fsConnectptr.i;
+ signal->theData[2] = rootfragrecptr.p->mytabptr; /* TABLE IDENTITY */
+ signal->theData[3] = tfid; /* FRAGMENT IDENTITY */
+ signal->theData[4] = lcpConnectptr.p->localCheckPid; /* CHECKPOINT ID */
+ signal->theData[5] = tmp1;
+ signal->theData[6] = tmp2;
+ sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA);
+ return;
+}//Dbacc::srOpenDataFileLoopLab()
+
+void Dbacc::srFsOpenConfLab(Signal* signal)
+{
+ fsConnectptr.p->fsState = WAIT_READ_PAGE_ZERO;
+ /* ------------------------ READ ZERO PAGE ---------- */
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 0x0;
+ /* FLAG = LIST MEM PAGES, LIST FILE PAGES */
+ signal->theData[4] = ZPAGE8_BASE_ADD;
+ signal->theData[5] = 1; /* NO OF PAGES */
+ signal->theData[6] = fragrecptr.p->zeroPagePtr; /* ZERO PAGE */
+ signal->theData[7] = 0; /* PAGE ZERO OF THE DATA FILE */
+ sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA);
+ return;
+}//Dbacc::srFsOpenConfLab()
+
+void Dbacc::srReadPageZeroLab(Signal* signal)
+{
+ Page8Ptr srzPageptr;
+
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ fragrecptr.p->activeDataFilePage = 1;
+ srzPageptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(srzPageptr, cpagesize, page8);
+ /* --------------------------------------------------------------------------------- */
+ // Check that the checksum of the zero page is ok.
+ /* --------------------------------------------------------------------------------- */
+ ccoPageptr.p = srzPageptr.p;
+ checksumControl(signal, (Uint32)0);
+ if (tresult > 0) {
+ jam();
+ return; // We will crash through a DEBUG_SIG
+ }//if
+
+ ndbrequire(srzPageptr.p->word32[ZPAGEZERO_FRAGID0] == rootfragrecptr.p->fragmentid[0]);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ if (fsConnectptr.p->activeFragId == 0) {
+ jam();
+ rootfragrecptr.p->fragmentid[1] = srzPageptr.p->word32[ZPAGEZERO_FRAGID1];
+ /* ---------------------------OPEN THE DATA FILE FOR NEXT LOCAL FRAGMENT ----------- ---- */
+ tfid = rootfragrecptr.p->fragmentid[1];
+ tmp = 1; /* LOCAL FRAG INDEX */
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ srOpenDataFileLoopLab(signal);
+ return;
+ } else {
+ jam();
+ lcpConnectptr.p->lcpstate = LCP_ACTIVE;
+ signal->theData[0] = lcpConnectptr.p->lcpUserptr;
+ signal->theData[1] = lcpConnectptr.i;
+ signal->theData[2] = 2; /* NO OF LOCAL FRAGMENTS */
+ signal->theData[3] = srzPageptr.p->word32[ZPAGEZERO_FRAGID0];
+ /* ROOTFRAGRECPTR:FRAGMENTID(0) */
+ signal->theData[4] = srzPageptr.p->word32[ZPAGEZERO_FRAGID1];
+ /* ROOTFRAGRECPTR:FRAGMENTID(1) */
+ signal->theData[5] = RNIL;
+ signal->theData[6] = RNIL;
+ signal->theData[7] = rootfragrecptr.p->fragmentptr[0];
+ signal->theData[8] = rootfragrecptr.p->fragmentptr[1];
+ signal->theData[9] = srzPageptr.p->word32[ZPAGEZERO_HASH_CHECK];
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_SR_FRAGIDCONF, signal, 10, JBB);
+ }//if
+ return;
+}//Dbacc::srReadPageZeroLab()
+
+void Dbacc::initFragAdd(Signal* signal,
+ Uint32 rootFragIndex,
+ Uint32 rootIndex,
+ FragmentrecPtr regFragPtr)
+{
+ const AccFragReq * const req = (AccFragReq*)&signal->theData[0];
+ Uint32 lhFragBits = req->lhFragBits + 1;
+ Uint32 minLoadFactor = (req->minLoadFactor * ZBUF_SIZE) / 100;
+ Uint32 maxLoadFactor = (req->maxLoadFactor * ZBUF_SIZE) / 100;
+ if (minLoadFactor >= maxLoadFactor) {
+ jam();
+ minLoadFactor = maxLoadFactor - 1;
+ }//if
+ regFragPtr.p->fragState = ACTIVEFRAG;
+ // NOTE: next line must match calculation in Dblqh::execLQHFRAGREQ
+ regFragPtr.p->myfid = (req->fragId << 1) | rootFragIndex;
+ regFragPtr.p->myroot = rootIndex;
+ regFragPtr.p->myTableId = req->tableId;
+ ndbrequire(req->kValue == 6);
+ regFragPtr.p->k = req->kValue; /* TK_SIZE = 6 IN THIS VERSION */
+ regFragPtr.p->expandCounter = 0;
+
+ /**
+ * Only allow shrink during SR
+ * - to make sure we don't run out of pages during REDO log execution
+ *
+ * Is later restored to 0 by LQH at end of REDO log execution
+ */
+ regFragPtr.p->expandFlag = (getNodeState().getSystemRestartInProgress()?1:0);
+ regFragPtr.p->p = 0;
+ regFragPtr.p->maxp = (1 << req->kValue) - 1;
+ regFragPtr.p->minloadfactor = minLoadFactor;
+ regFragPtr.p->maxloadfactor = maxLoadFactor;
+ regFragPtr.p->slack = (regFragPtr.p->maxp + 1) * maxLoadFactor;
+ regFragPtr.p->lhfragbits = lhFragBits;
+ regFragPtr.p->lhdirbits = 0;
+ regFragPtr.p->hashcheckbit = 0; //lhFragBits;
+ regFragPtr.p->localkeylen = req->localKeyLen;
+ regFragPtr.p->nodetype = (req->reqInfo >> 4) & 0x3;
+ regFragPtr.p->lastOverIndex = 0;
+ regFragPtr.p->dirsize = 1;
+ regFragPtr.p->loadingFlag = ZFALSE;
+ regFragPtr.p->keyLength = req->keyLength;
+ ndbrequire(req->keyLength != 0);
+ regFragPtr.p->elementLength = ZELEM_HEAD_SIZE + regFragPtr.p->localkeylen;
+ Uint32 Tmp1 = (regFragPtr.p->maxp + 1) + regFragPtr.p->p;
+ Uint32 Tmp2 = regFragPtr.p->maxloadfactor - regFragPtr.p->minloadfactor;
+ Tmp2 = Tmp1 * Tmp2;
+ regFragPtr.p->slackCheck = Tmp2;
+}//Dbacc::initFragAdd()
+
+void Dbacc::initFragGeneral(FragmentrecPtr regFragPtr)
+{
+ regFragPtr.p->directory = RNIL;
+ regFragPtr.p->overflowdir = RNIL;
+ regFragPtr.p->fsConnPtr = RNIL;
+ regFragPtr.p->firstOverflowRec = RNIL;
+ regFragPtr.p->lastOverflowRec = RNIL;
+ regFragPtr.p->firstWaitInQueOp = RNIL;
+ regFragPtr.p->lastWaitInQueOp = RNIL;
+ regFragPtr.p->sentWaitInQueOp = RNIL;
+ regFragPtr.p->lockOwnersList = RNIL;
+ regFragPtr.p->firstFreeDirindexRec = RNIL;
+ regFragPtr.p->zeroPagePtr = RNIL;
+
+ regFragPtr.p->activeDataPage = 0;
+ regFragPtr.p->createLcp = ZFALSE;
+ regFragPtr.p->stopQueOp = ZFALSE;
+ regFragPtr.p->hasCharAttr = ZFALSE;
+ regFragPtr.p->nextAllocPage = 0;
+ regFragPtr.p->nrWaitWriteUndoExit = 0;
+ regFragPtr.p->lastUndoIsStored = ZFALSE;
+ regFragPtr.p->loadingFlag = ZFALSE;
+ regFragPtr.p->fragState = FREEFRAG;
+ for (Uint32 i = 0; i < ZWRITEPAGESIZE; i++) {
+ regFragPtr.p->datapages[i] = RNIL;
+ }//for
+ for (Uint32 j = 0; j < 4; j++) {
+ regFragPtr.p->longKeyPageArray[j] = RNIL;
+ }//for
+}//Dbacc::initFragGeneral()
+
+void Dbacc::initFragSr(FragmentrecPtr regFragPtr, Page8Ptr regPagePtr)
+{
+ regFragPtr.p->prevUndoposition = regPagePtr.p->word32[ZPAGEZERO_PREV_UNDOP];
+ regFragPtr.p->noOfStoredOverPages = regPagePtr.p->word32[ZPAGEZERO_NO_OVER_PAGE];
+ regFragPtr.p->noStoredPages = regPagePtr.p->word32[ZPAGEZERO_NO_PAGES];
+ regFragPtr.p->dirsize = regPagePtr.p->word32[ZPAGEZERO_DIRSIZE];
+ regFragPtr.p->expandCounter = regPagePtr.p->word32[ZPAGEZERO_EXPCOUNTER];
+ regFragPtr.p->slack = regPagePtr.p->word32[ZPAGEZERO_SLACK];
+ regFragPtr.p->hashcheckbit = regPagePtr.p->word32[ZPAGEZERO_HASHCHECKBIT];
+ regFragPtr.p->k = regPagePtr.p->word32[ZPAGEZERO_K];
+ regFragPtr.p->lhfragbits = regPagePtr.p->word32[ZPAGEZERO_LHFRAGBITS];
+ regFragPtr.p->lhdirbits = regPagePtr.p->word32[ZPAGEZERO_LHDIRBITS];
+ regFragPtr.p->localkeylen = regPagePtr.p->word32[ZPAGEZERO_LOCALKEYLEN];
+ regFragPtr.p->maxp = regPagePtr.p->word32[ZPAGEZERO_MAXP];
+ regFragPtr.p->maxloadfactor = regPagePtr.p->word32[ZPAGEZERO_MAXLOADFACTOR];
+ regFragPtr.p->minloadfactor = regPagePtr.p->word32[ZPAGEZERO_MINLOADFACTOR];
+ regFragPtr.p->myfid = regPagePtr.p->word32[ZPAGEZERO_MYFID];
+ regFragPtr.p->lastOverIndex = regPagePtr.p->word32[ZPAGEZERO_LAST_OVER_INDEX];
+ regFragPtr.p->nodetype = regPagePtr.p->word32[ZPAGEZERO_NODETYPE];
+ regFragPtr.p->p = regPagePtr.p->word32[ZPAGEZERO_P];
+ regFragPtr.p->elementLength = regPagePtr.p->word32[ZPAGEZERO_ELEMENT_LENGTH];
+ regFragPtr.p->keyLength = regPagePtr.p->word32[ZPAGEZERO_KEY_LENGTH];
+ regFragPtr.p->slackCheck = regPagePtr.p->word32[ZPAGEZERO_SLACK_CHECK];
+
+ regFragPtr.p->loadingFlag = ZTRUE;
+
+}//Dbacc::initFragSr()
+
+void Dbacc::initFragPageZero(FragmentrecPtr regFragPtr, Page8Ptr regPagePtr)
+{
+ //------------------------------------------------------------------
+ // PREV_UNDOP, NEXT_UNDO_FILE, NO_OVER_PAGE, NO_PAGES
+ // is set at end of copy phase
+ //------------------------------------------------------------------
+ regPagePtr.p->word32[ZPAGEZERO_DIRSIZE] = regFragPtr.p->dirsize;
+ regPagePtr.p->word32[ZPAGEZERO_EXPCOUNTER] = regFragPtr.p->expandCounter;
+ regPagePtr.p->word32[ZPAGEZERO_SLACK] = regFragPtr.p->slack;
+ regPagePtr.p->word32[ZPAGEZERO_HASHCHECKBIT] = regFragPtr.p->hashcheckbit;
+ regPagePtr.p->word32[ZPAGEZERO_K] = regFragPtr.p->k;
+ regPagePtr.p->word32[ZPAGEZERO_LHFRAGBITS] = regFragPtr.p->lhfragbits;
+ regPagePtr.p->word32[ZPAGEZERO_LHDIRBITS] = regFragPtr.p->lhdirbits;
+ regPagePtr.p->word32[ZPAGEZERO_LOCALKEYLEN] = regFragPtr.p->localkeylen;
+ regPagePtr.p->word32[ZPAGEZERO_MAXP] = regFragPtr.p->maxp;
+ regPagePtr.p->word32[ZPAGEZERO_MAXLOADFACTOR] = regFragPtr.p->maxloadfactor;
+ regPagePtr.p->word32[ZPAGEZERO_MINLOADFACTOR] = regFragPtr.p->minloadfactor;
+ regPagePtr.p->word32[ZPAGEZERO_MYFID] = regFragPtr.p->myfid;
+ regPagePtr.p->word32[ZPAGEZERO_LAST_OVER_INDEX] = regFragPtr.p->lastOverIndex;
+ regPagePtr.p->word32[ZPAGEZERO_NODETYPE] = regFragPtr.p->nodetype;
+ regPagePtr.p->word32[ZPAGEZERO_P] = regFragPtr.p->p;
+ regPagePtr.p->word32[ZPAGEZERO_ELEMENT_LENGTH] = regFragPtr.p->elementLength;
+ regPagePtr.p->word32[ZPAGEZERO_KEY_LENGTH] = regFragPtr.p->keyLength;
+ regPagePtr.p->word32[ZPAGEZERO_SLACK_CHECK] = regFragPtr.p->slackCheck;
+}//Dbacc::initFragPageZero()
+
+void Dbacc::initRootFragPageZero(RootfragmentrecPtr rootPtr, Page8Ptr regPagePtr)
+{
+ regPagePtr.p->word32[ZPAGEZERO_TABID] = rootPtr.p->mytabptr;
+ regPagePtr.p->word32[ZPAGEZERO_FRAGID0] = rootPtr.p->fragmentid[0];
+ regPagePtr.p->word32[ZPAGEZERO_FRAGID1] = rootPtr.p->fragmentid[1];
+ regPagePtr.p->word32[ZPAGEZERO_HASH_CHECK] = rootPtr.p->roothashcheck;
+ regPagePtr.p->word32[ZPAGEZERO_NO_OF_ELEMENTS] = rootPtr.p->noOfElements;
+}//Dbacc::initRootFragPageZero()
+
+void Dbacc::initRootFragSr(RootfragmentrecPtr rootPtr, Page8Ptr regPagePtr)
+{
+ rootPtr.p->roothashcheck = regPagePtr.p->word32[ZPAGEZERO_HASH_CHECK];
+ rootPtr.p->noOfElements = regPagePtr.p->word32[ZPAGEZERO_NO_OF_ELEMENTS];
+}//Dbacc::initRootFragSr()
+
+/* ******************--------------------------------------------------------------- */
+/* ACC_SRREQ SYSTEM RESTART OF A LOCAL CHECK POINT */
+/* SENDER: LQH, LEVEL B */
+/* ENTER ACC_SRREQ WITH */
+/* LCP_CONNECTPTR, OPERATION RECORD PTR */
+/* TMP2, LQH'S LOCAL FRAG CHECK VALUE */
+/* TFID, LOCAL FRAG ID */
+/* TMP1, LOCAL CHECKPOINT ID */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_SRREQ PERFORM A LOCAL CHECK POINT */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACC_SRREQ(Signal* signal)
+{
+ Page8Ptr asrPageidptr;
+ jamEntry();
+ lcpConnectptr.i = signal->theData[0];
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ Uint32 lqhPtr = signal->theData[1];
+ Uint32 fragId = signal->theData[2];
+ Uint32 lcpId = signal->theData[3];
+ tresult = 0;
+ ndbrequire(lcpConnectptr.p->lcpstate == LCP_ACTIVE);
+ rootfragrecptr.i = lcpConnectptr.p->rootrecptr;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->fragmentid[0] == fragId) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ } else {
+ ndbrequire(rootfragrecptr.p->fragmentid[1] == fragId);
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ }//if
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->lcpLqhPtr = lqhPtr;
+ fragrecptr.p->localCheckpId = lcpId;
+ asrPageidptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(asrPageidptr, cpagesize, page8);
+ ndbrequire(asrPageidptr.p->word32[ZPAGEZERO_TABID] == rootfragrecptr.p->mytabptr);
+ ndbrequire(asrPageidptr.p->word32[ZPAGEZERO_FRAGID0] == rootfragrecptr.p->fragmentid[0]);
+ ndbrequire(asrPageidptr.p->word32[ZPAGEZERO_FRAGID1] == rootfragrecptr.p->fragmentid[1]);
+ initRootFragSr(rootfragrecptr, asrPageidptr);
+ initFragSr(fragrecptr, asrPageidptr);
+ for (Uint32 i = 0; i < ZMAX_UNDO_VERSION; i++) {
+ jam();
+ if (csrVersList[i] != RNIL) {
+ jam();
+ srVersionPtr.i = csrVersList[i];
+ ptrCheckGuard(srVersionPtr, csrVersionRecSize, srVersionRec);
+ if (fragrecptr.p->localCheckpId == srVersionPtr.p->checkPointId) {
+ jam();
+ ndbrequire(srVersionPtr.p->checkPointId == asrPageidptr.p->word32[ZPAGEZERO_NEXT_UNDO_FILE]);
+ /*--------------------------------------------------------------------------------*/
+ /* SINCE -1 IS THE END OF LOG CODE WE MUST TREAT THIS CODE WITH CARE. WHEN */
+ /* COMPARING IT IS LARGER THAN EVERYTHING ELSE BUT SHOULD BE TREATED AS THE */
+ /* SMALLEST POSSIBLE VALUE, MEANING EMPTY. */
+ /*--------------------------------------------------------------------------------*/
+ if (fragrecptr.p->prevUndoposition != cminusOne) {
+ if (srVersionPtr.p->prevAddress < fragrecptr.p->prevUndoposition) {
+ jam();
+ srVersionPtr.p->prevAddress = fragrecptr.p->prevUndoposition;
+ } else if (srVersionPtr.p->prevAddress == cminusOne) {
+ jam();
+ srVersionPtr.p->prevAddress = fragrecptr.p->prevUndoposition;
+ }//if
+ }//if
+ srAllocPage0011Lab(signal);
+ return;
+ }//if
+ } else {
+ jam();
+ seizeSrVerRec(signal);
+ srVersionPtr.p->checkPointId = fragrecptr.p->localCheckpId;
+ srVersionPtr.p->prevAddress = fragrecptr.p->prevUndoposition;
+ csrVersList[i] = srVersionPtr.i;
+ srAllocPage0011Lab(signal);
+ return;
+ }//if
+ }//for
+ ndbrequire(false);
+}//Dbacc::execACC_SRREQ()
+
+void
+Dbacc::releaseLogicalPage(Fragmentrec * fragP, Uint32 logicalPageId){
+ Ptr<struct DirRange> dirRangePtr;
+ dirRangePtr.i = fragP->directory;
+ ptrCheckGuard(dirRangePtr, cdirrangesize, dirRange);
+
+ const Uint32 lp1 = logicalPageId >> 8;
+ const Uint32 lp2 = logicalPageId & 0xFF;
+ ndbrequire(lp1 < 256);
+
+ Ptr<struct Directoryarray> dirArrPtr;
+ dirArrPtr.i = dirRangePtr.p->dirArray[lp1];
+ ptrCheckGuard(dirArrPtr, cdirarraysize, directoryarray);
+
+ const Uint32 physicalPageId = dirArrPtr.p->pagep[lp2];
+
+ rpPageptr.i = physicalPageId;
+ ptrCheckGuard(rpPageptr, cpagesize, page8);
+ releasePage(0);
+
+ dirArrPtr.p->pagep[lp2] = RNIL;
+}
+
+void Dbacc::srAllocPage0011Lab(Signal* signal)
+{
+ releaseLogicalPage(fragrecptr.p, 0);
+
+#if JONAS
+ ndbrequire(cfirstfreeDirrange != RNIL);
+ seizeDirrange(signal);
+ fragrecptr.p->directory = newDirRangePtr.i;
+ ndbrequire(cfirstfreeDirrange != RNIL);
+ seizeDirrange(signal);
+ fragrecptr.p->overflowdir = newDirRangePtr.i;
+ seizeDirectory(signal);
+ ndbrequire(tresult < ZLIMIT_OF_ERROR);
+ newDirRangePtr.p->dirArray[0] = sdDirptr.i;
+#endif
+
+ fragrecptr.p->nextAllocPage = 0;
+ fragrecptr.p->fragState = SR_READ_PAGES;
+ srReadPagesLab(signal);
+ return;
+}//Dbacc::srAllocPage0011Lab()
+
+void Dbacc::srReadPagesLab(Signal* signal)
+{
+ if (fragrecptr.p->nextAllocPage >= fragrecptr.p->noStoredPages) {
+ /*--------------------------------------------------------------------------------*/
+ /* WE HAVE NOW READ ALL NORMAL PAGES FROM THE FILE. */
+ /*--------------------------------------------------------------------------------*/
+ if (fragrecptr.p->nextAllocPage == fragrecptr.p->dirsize) {
+ jam();
+ /*--------------------------------------------------------------------------------*/
+ /* WE HAVE NOW READ ALL NORMAL PAGES AND ALLOCATED ALL THE NEEDED PAGES. */
+ /*--------------------------------------------------------------------------------*/
+ fragrecptr.p->nextAllocPage = 0; /* THE NEXT OVER FLOW PAGE WHICH WILL BE READ */
+ fragrecptr.p->fragState = SR_READ_OVER_PAGES;
+ srReadOverPagesLab(signal);
+ } else {
+ ndbrequire(fragrecptr.p->nextAllocPage < fragrecptr.p->dirsize);
+ jam();
+ /*--------------------------------------------------------------------------------*/
+ /* WE NEEDED TO ALLOCATE PAGES THAT WERE DEALLOCATED DURING THE LOCAL */
+ /* CHECKPOINT. */
+ /* ALLOCATE THE PAGE AND INITIALISE IT. THEN WE INSERT A REAL-TIME BREAK. */
+ /*--------------------------------------------------------------------------------*/
+ seizePage(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ tipPageId = fragrecptr.p->nextAllocPage;
+ inpPageptr.i = spPageptr.i;
+ ptrCheckGuard(inpPageptr, cpagesize, page8);
+ initPage(signal);
+ fragrecptr.p->noOfExpectedPages = 1;
+ fragrecptr.p->datapages[0] = spPageptr.i;
+ signal->theData[0] = ZSR_READ_PAGES_ALLOC;
+ signal->theData[1] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 2, JBB);
+ }//if
+ return;
+ }//if
+ Uint32 limitLoop;
+ if ((fragrecptr.p->noStoredPages - fragrecptr.p->nextAllocPage) < ZWRITEPAGESIZE) {
+ jam();
+ limitLoop = fragrecptr.p->noStoredPages - fragrecptr.p->nextAllocPage;
+ } else {
+ jam();
+ limitLoop = ZWRITEPAGESIZE;
+ }//if
+ ndbrequire(limitLoop <= 8);
+ for (Uint32 i = 0; i < limitLoop; i++) {
+ jam();
+ seizePage(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ fragrecptr.p->datapages[i] = spPageptr.i;
+ signal->theData[i + 6] = spPageptr.i;
+ }//for
+ signal->theData[limitLoop + 6] = fragrecptr.p->activeDataFilePage;
+ fragrecptr.p->noOfExpectedPages = limitLoop;
+ /* -----------------SEND READ PAGES SIGNAL TO THE FILE MANAGER --------- */
+ fsConnectptr.i = fragrecptr.p->fsConnPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ fsConnectptr.p->fsState = WAIT_READ_DATA;
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 2;
+ /* FLAG = LIST MEM PAGES, RANGE OF FILE PAGES */
+ signal->theData[4] = ZPAGE8_BASE_ADD;
+ signal->theData[5] = fragrecptr.p->noOfExpectedPages;
+ sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA);
+ return;
+}//Dbacc::srReadPagesLab()
+
+void Dbacc::storeDataPageInDirectoryLab(Signal* signal)
+{
+ fragrecptr.p->activeDataFilePage += fragrecptr.p->noOfExpectedPages;
+ srReadPagesAllocLab(signal);
+ return;
+}//Dbacc::storeDataPageInDirectoryLab()
+
+void Dbacc::srReadPagesAllocLab(Signal* signal)
+{
+ DirRangePtr srpDirRangePtr;
+ DirectoryarrayPtr srpDirptr;
+ DirectoryarrayPtr srpOverflowDirptr;
+ Page8Ptr srpPageidptr;
+
+ if (fragrecptr.p->fragState == SR_READ_PAGES) {
+ jam();
+ for (Uint32 i = 0; i < fragrecptr.p->noOfExpectedPages; i++) {
+ jam();
+ tmpP = fragrecptr.p->nextAllocPage;
+ srpDirRangePtr.i = fragrecptr.p->directory;
+ tmpP2 = tmpP >> 8;
+ tmp = tmpP & 0xff;
+ ptrCheckGuard(srpDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tmpP2, 256);
+ if (srpDirRangePtr.p->dirArray[tmpP2] == RNIL) {
+ seizeDirectory(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ srpDirptr.i = sdDirptr.i;
+ srpDirRangePtr.p->dirArray[tmpP2] = srpDirptr.i;
+ } else {
+ jam();
+ srpDirptr.i = srpDirRangePtr.p->dirArray[tmpP2];
+ }//if
+ ptrCheckGuard(srpDirptr, cdirarraysize, directoryarray);
+ arrGuard(i, 8);
+ srpDirptr.p->pagep[tmp] = fragrecptr.p->datapages[i];
+ srpPageidptr.i = fragrecptr.p->datapages[i];
+ ptrCheckGuard(srpPageidptr, cpagesize, page8);
+ ndbrequire(srpPageidptr.p->word32[ZPOS_PAGE_ID] == fragrecptr.p->nextAllocPage);
+ ndbrequire(((srpPageidptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == 0);
+ ccoPageptr.p = srpPageidptr.p;
+ checksumControl(signal, (Uint32)1);
+ if (tresult > 0) {
+ jam();
+ return; // We will crash through a DEBUG_SIG
+ }//if
+ dbgWord32(srpPageidptr, ZPOS_OVERFLOWREC, RNIL);
+ srpPageidptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+ fragrecptr.p->datapages[i] = RNIL;
+ fragrecptr.p->nextAllocPage++;
+ }//for
+ srReadPagesLab(signal);
+ return;
+ } else {
+ ndbrequire(fragrecptr.p->fragState == SR_READ_OVER_PAGES);
+ for (Uint32 i = 0; i < fragrecptr.p->noOfExpectedPages; i++) {
+ jam();
+ arrGuard(i, 8);
+ srpPageidptr.i = fragrecptr.p->datapages[i];
+ ptrCheckGuard(srpPageidptr, cpagesize, page8);
+ tmpP = srpPageidptr.p->word32[ZPOS_PAGE_ID]; /* DIR INDEX OF THE OVERFLOW PAGE */
+ /*--------------------------------------------------------------------------------*/
+ /* IT IS POSSIBLE THAT WE HAVE LOGICAL PAGES WHICH ARE NOT PART OF THE LOCAL*/
+ /* CHECKPOINT. THUS WE USE THE LOGICAL PAGE ID FROM THE PAGE HERE. */
+ /*--------------------------------------------------------------------------------*/
+ srpDirRangePtr.i = fragrecptr.p->overflowdir;
+ tmpP2 = tmpP >> 8;
+ tmpP = tmpP & 0xff;
+ ptrCheckGuard(srpDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tmpP2, 256);
+ if (srpDirRangePtr.p->dirArray[tmpP2] == RNIL) {
+ jam();
+ seizeDirectory(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ srpDirRangePtr.p->dirArray[tmpP2] = sdDirptr.i;
+ }//if
+ srpOverflowDirptr.i = srpDirRangePtr.p->dirArray[tmpP2];
+ ndbrequire(((srpPageidptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) != 0);
+ ndbrequire(((srpPageidptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) != 3);
+ ptrCheckGuard(srpOverflowDirptr, cdirarraysize, directoryarray);
+ ndbrequire(srpOverflowDirptr.p->pagep[tmpP] == RNIL);
+ srpOverflowDirptr.p->pagep[tmpP] = srpPageidptr.i;
+ ccoPageptr.p = srpPageidptr.p;
+ checksumControl(signal, (Uint32)1);
+ ndbrequire(tresult == 0);
+ dbgWord32(srpPageidptr, ZPOS_OVERFLOWREC, RNIL);
+ srpPageidptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+ fragrecptr.p->nextAllocPage++;
+ }//for
+ srReadOverPagesLab(signal);
+ return;
+ }//if
+}//Dbacc::srReadPagesAllocLab()
+
+void Dbacc::srReadOverPagesLab(Signal* signal)
+{
+ if (fragrecptr.p->nextAllocPage >= fragrecptr.p->noOfStoredOverPages) {
+ fragrecptr.p->nextAllocPage = 0;
+ if (fragrecptr.p->prevUndoposition == cminusOne) {
+ jam();
+ /* ************************ */
+ /* ACC_OVER_REC */
+ /* ************************ */
+ /*--------------------------------------------------------------------------------*/
+ /* UPDATE FREE LIST OF OVERFLOW PAGES AS PART OF SYSTEM RESTART AFTER */
+ /* READING PAGES AND EXECUTING THE UNDO LOG. */
+ /*--------------------------------------------------------------------------------*/
+ signal->theData[0] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_OVER_REC, signal, 1, JBB);
+ } else {
+ jam();
+ srCloseDataFileLab(signal);
+ }//if
+ return;
+ }//if
+ Uint32 limitLoop;
+ if ((fragrecptr.p->noOfStoredOverPages - fragrecptr.p->nextAllocPage) < ZWRITEPAGESIZE) {
+ jam();
+ limitLoop = fragrecptr.p->noOfStoredOverPages - fragrecptr.p->nextAllocPage;
+ } else {
+ jam();
+ limitLoop = ZWRITEPAGESIZE;
+ }//if
+ ndbrequire(limitLoop <= 8);
+ for (Uint32 i = 0; i < limitLoop; i++) {
+ jam();
+ seizePage(signal);
+ ndbrequire(tresult <= ZLIMIT_OF_ERROR);
+ fragrecptr.p->datapages[i] = spPageptr.i;
+ signal->theData[i + 6] = spPageptr.i;
+ }//for
+ fragrecptr.p->noOfExpectedPages = limitLoop;
+ signal->theData[limitLoop + 6] = fragrecptr.p->activeDataFilePage;
+ /* -----------------SEND READ PAGES SIGNAL TO THE FILE MANAGER --------- */
+ fsConnectptr.i = fragrecptr.p->fsConnPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ fsConnectptr.p->fsState = WAIT_READ_DATA;
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 2;
+ signal->theData[4] = ZPAGE8_BASE_ADD;
+ signal->theData[5] = fragrecptr.p->noOfExpectedPages;
+ sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA);
+ return;
+}//Dbacc::srReadOverPagesLab()
+
+void Dbacc::srCloseDataFileLab(Signal* signal)
+{
+ fsConnectptr.i = fragrecptr.p->fsConnPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ fsConnectptr.p->fsState = SR_CLOSE_DATA;
+ /* ************************ */
+ /* FSCLOSEREQ */
+ /* ************************ */
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 0;
+ sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA);
+ return;
+}//Dbacc::srCloseDataFileLab()
+
+/* ************************ */
+/* ACC_SRCONF */
+/* ************************ */
+void Dbacc::sendaccSrconfLab(Signal* signal)
+{
+ fragrecptr.i = fsConnectptr.p->fragrecPtr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ releaseFsConnRec(signal);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ lcpConnectptr.i = rootfragrecptr.p->lcpPtr;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ fragrecptr.p->fragState = ACTIVEFRAG;
+ fragrecptr.p->fsConnPtr = RNIL;
+ for (Uint32 i = 0; i < ZWRITEPAGESIZE; i++) {
+ fragrecptr.p->datapages[i] = RNIL;
+ }//for
+ rlpPageptr.i = fragrecptr.p->zeroPagePtr;
+ ptrCheckGuard(rlpPageptr, cpagesize, page8);
+ releaseLcpPage(signal);
+ fragrecptr.p->zeroPagePtr = RNIL;
+ signal->theData[0] = fragrecptr.p->lcpLqhPtr;
+ sendSignal(lcpConnectptr.p->lcpUserblockref, GSN_ACC_SRCONF, signal, 1, JBB);
+ lcpConnectptr.p->noOfLcpConf++;
+ if (lcpConnectptr.p->noOfLcpConf == 2) {
+ jam();
+ releaseLcpConnectRec(signal);
+ rootfragrecptr.p->lcpPtr = RNIL;
+ rootfragrecptr.p->rootState = ACTIVEROOT;
+ }//if
+ return;
+}//Dbacc::sendaccSrconfLab()
+
+/* --------------------------------------------------------------------------------- */
+/* CHECKSUM_CONTROL */
+/* INPUT: CCO_PAGEPTR */
+/* OUTPUT: TRESULT */
+/* */
+/* CHECK THAT CHECKSUM IN PAGE IS CORRECT TO ENSURE THAT NO ONE HAS CORRUPTED */
+/* THE PAGE INFORMATION. WHEN CALCULATING THE CHECKSUM WE REMOVE THE CHECKSUM */
+/* ITSELF FROM THE CHECKSUM BY XOR'ING THE CHECKSUM TWICE. WHEN CALCULATING */
+/* THE CHECKSUM THE CHECKSUM WORD IS ZERO WHICH MEANS NO CHANGE FROM XOR'ING. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::checksumControl(Signal* signal, Uint32 checkPage)
+{
+ Uint32 Tchs;
+ Uint32 tccoIndex;
+ Uint32 Ti;
+ Uint32 Tmp1;
+ Uint32 Tmp2;
+ Uint32 Tmp3;
+ Uint32 Tmp4;
+ Uint32 Tlimit;
+
+ Tchs = 0;
+ for (Ti = 0; Ti < 32 ; Ti++) {
+ Tlimit = 16 + (Ti << 6);
+ for (tccoIndex = (Ti << 6); tccoIndex < Tlimit; tccoIndex ++) {
+ Tmp1 = ccoPageptr.p->word32[tccoIndex];
+ Tmp2 = ccoPageptr.p->word32[tccoIndex + 16];
+ Tmp3 = ccoPageptr.p->word32[tccoIndex + 32];
+ Tmp4 = ccoPageptr.p->word32[tccoIndex + 48];
+
+ Tchs = Tchs ^ Tmp1;
+ Tchs = Tchs ^ Tmp2;
+ Tchs = Tchs ^ Tmp3;
+ Tchs = Tchs ^ Tmp4;
+ }//for
+ }//for
+ if (Tchs == 0) {
+ tresult = 0;
+ if (checkPage != 0) {
+ jam();
+ lcnCopyPageptr.p = ccoPageptr.p;
+ srCheckPage(signal);
+ }//if
+ } else {
+ tresult = 1;
+ }//if
+ if (tresult != 0) {
+ jam();
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ signal->theData[0] = RNIL;
+ signal->theData[1] = rootfragrecptr.p->mytabptr;
+ signal->theData[2] = fragrecptr.p->myfid;
+ signal->theData[3] = ccoPageptr.p->word32[ZPOS_PAGE_ID];
+ signal->theData[4] = tlupElemIndex;
+ signal->theData[5] = ccoPageptr.p->word32[ZPOS_PAGE_TYPE];
+ signal->theData[6] = tresult;
+ sendSignal(cownBlockref, GSN_DEBUG_SIG, signal, 7, JBA);
+ }//if
+}//Dbacc::checksumControl()
+
+/* ******************--------------------------------------------------------------- */
+/* START_RECREQ REQUEST TO START UNDO PROCESS */
+/* SENDER: LQH, LEVEL B */
+/* ENTER START_RECREQ WITH */
+/* CLQH_PTR, LQH CONNECTION PTR */
+/* CLQH_BLOCK_REF, LQH BLOCK REFERENCE */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* START_RECREQ REQUEST TO START UNDO PROCESS */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execSTART_RECREQ(Signal* signal)
+{
+ jamEntry();
+ clqhPtr = signal->theData[0]; /* LQH CONNECTION PTR */
+ clqhBlockRef = signal->theData[1]; /* LQH BLOCK REFERENCE */
+ tresult = 0; /* 0= FALSE,1= TRUE,> ZLIMIT_OF_ERROR =ERRORCODE */
+ for (int i = 0; i < UndoHeader::ZNO_UNDORECORD_TYPES; i++)
+ cSrUndoRecords[i] = 0;
+ startUndoLab(signal);
+ return;
+}//Dbacc::execSTART_RECREQ()
+
+void Dbacc::startUndoLab(Signal* signal)
+{
+ cundoLogActive = ZTRUE;
+ /* ----- OPEN UNDO FILES --------- */
+ for (tmp = 0; tmp <= ZMAX_UNDO_VERSION - 1; tmp++) {
+ jam();
+ if (csrVersList[tmp] != RNIL) {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* SELECT THE NEXT SYSTEM RESTART RECORD WHICH CONTAINS AN UNDO LOG */
+ /* THAT NEEDS TO BE EXECUTED AND SET UP THE DATA TO EXECUTE IT. */
+ /*---------------------------------------------------------------------------*/
+ srVersionPtr.i = csrVersList[tmp];
+ csrVersList[tmp] = RNIL;
+ ptrCheckGuard(srVersionPtr, csrVersionRecSize, srVersionRec);
+ cactiveUndoFilePage = srVersionPtr.p->prevAddress >> 13;
+ cprevUndoaddress = srVersionPtr.p->prevAddress;
+ cactiveCheckpId = srVersionPtr.p->checkPointId;
+
+ releaseSrRec(signal);
+ startActiveUndo(signal);
+ return;
+ }//if
+ }//for
+
+ // Send report of how many undo log records where executed
+ signal->theData[0] = NDB_LE_UNDORecordsExecuted;
+ signal->theData[1] = DBACC; // From block
+ signal->theData[2] = 0; // Total records executed
+ for (int i = 0; i < 10; i++){
+ if (i < UndoHeader::ZNO_UNDORECORD_TYPES){
+ signal->theData[i+3] = cSrUndoRecords[i];
+ signal->theData[2] += cSrUndoRecords[i];
+ }else{
+ signal->theData[i+3] = 0;
+ }
+ }
+ sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 12, JBB);
+
+ /* ******************************< */
+ /* START_RECCONF */
+ /* ******************************< */
+ /*---------------------------------------------------------------------------*/
+ /* REPORT COMPLETION OF UNDO LOG EXECUTION. */
+ /*---------------------------------------------------------------------------*/
+ cundoLogActive = ZFALSE;
+ signal->theData[0] = clqhPtr;
+ sendSignal(clqhBlockRef, GSN_START_RECCONF, signal, 1, JBB);
+ /* LQH CONNECTION PTR */
+ return;
+}//Dbacc::startUndoLab()
+
+/*---------------------------------------------------------------------------*/
+/* START THE UNDO OF AN UNDO LOG FILE BY OPENING THE UNDO LOG FILE. */
+/*---------------------------------------------------------------------------*/
+void Dbacc::startActiveUndo(Signal* signal)
+{
+ if (cprevUndoaddress == cminusOne) {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* THERE WAS NO UNDO LOG INFORMATION IN THIS LOG FILE. WE GET THE NEXT */
+ /* OR REPORT COMPLETION. */
+ /*---------------------------------------------------------------------------*/
+ signal->theData[0] = ZSTART_UNDO;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 1, JBB);
+ } else {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* OPEN THE LOG FILE PERTAINING TO THIS UNDO LOG. */
+ /*---------------------------------------------------------------------------*/
+ if (cfsFirstfreeconnect == RNIL) {
+ jam();
+ sendSystemerror(signal);
+ }//if
+ seizeFsConnectRec(signal);
+ cactiveSrFsPtr = fsConnectptr.i;
+ fsConnectptr.p->fsState = OPEN_UNDO_FILE_SR;
+ fsConnectptr.p->fsPart = 0;
+ tmp1 = 1; /* FILE VERSION ? */
+ tmp1 = (tmp1 << 8) + ZLOCALLOGFILE; /* .LOCLOG = 2 */
+ tmp1 = (tmp1 << 8) + 4; /* ROOT DIRECTORY = D4 */
+ tmp1 = (tmp1 << 8) + fsConnectptr.p->fsPart; /* P2 */
+ tmp2 = 0x0; /* D7 DON'T CREATE , READ ONLY */
+ /* DON'T TRUNCATE TO ZERO */
+ /* ---FILE NAME "D4"/"DBACC"/LCP_CONNECTPTR:LOCAL_CHECK_PID/FS_CONNECTPTR:FS_PART".LOCLOG-- */
+ /* ************************ */
+ /* FSOPENREQ */
+ /* ************************ */
+ signal->theData[0] = cownBlockref;
+ signal->theData[1] = fsConnectptr.i;
+ signal->theData[2] = cminusOne; /* #FFFFFFFF */
+ signal->theData[3] = cminusOne; /* #FFFFFFFF */
+ signal->theData[4] = cactiveCheckpId; /* CHECKPOINT VERSION */
+ signal->theData[5] = tmp1;
+ signal->theData[6] = tmp2;
+ sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA);
+ }//if
+}//Dbacc::startActiveUndo()
+
+/* ------- READ A GROUP OF UNDO PAGES --------------- */
+void Dbacc::srStartUndoLab(Signal* signal)
+{
+ /*---------------------------------------------------------------------------*/
+ /* ALL LOG FILES HAVE BEEN OPENED. WE CAN NOW READ DATA FROM THE LAST */
+ /* PAGE IN THE LAST LOG FILE AND BACKWARDS UNTIL WE REACH THE VERY */
+ /* FIRST UNDO LOG RECORD. */
+ /*---------------------------------------------------------------------------*/
+ if (cactiveUndoFilePage >= ZWRITE_UNDOPAGESIZE) {
+ jam();
+ tmp1 = ZWRITE_UNDOPAGESIZE; /* NO OF READ UNDO PAGES */
+ cactiveSrUndoPage = ZWRITE_UNDOPAGESIZE - 1; /* LAST PAGE */
+ } else {
+ jam();
+ tmp1 = cactiveUndoFilePage + 1; /* NO OF READ UNDO PAGES */
+ cactiveSrUndoPage = cactiveUndoFilePage;
+ }//if
+ fsConnectptr.i = cactiveSrFsPtr;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ signal->theData[0] = fsConnectptr.p->fsPtr;
+ signal->theData[1] = cownBlockref;
+ signal->theData[2] = fsConnectptr.i;
+ signal->theData[3] = 0;
+ /* FLAG = LIST MEM PAGES, LIST FILE PAGES */
+ signal->theData[4] = ZUNDOPAGE_BASE_ADD;
+ signal->theData[5] = tmp1;
+ signal->theData[6] = 0;
+ signal->theData[7] = (cactiveUndoFilePage - tmp1) + 1;
+ signal->theData[8] = 1;
+ signal->theData[9] = cactiveUndoFilePage;
+
+ sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 10, JBA);
+ if (tmp1 > cactiveUndoFilePage) {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* THIS IS THE LAST READ IN THIS LOG FILE. WE SET THE ACTIVE FILE */
+ /* POINTER. IF IT IS THE FIRST WE SHOULD NEVER ATTEMPT ANY MORE READS */
+ /* SINCE WE SHOULD ENCOUNTER A FIRST LOG RECORD WITH PREVIOUS PAGE ID */
+ /* EQUAL TO RNIL. */
+ /*---------------------------------------------------------------------------*/
+ cactiveSrFsPtr = RNIL;
+ fsConnectptr.p->fsState = READ_UNDO_PAGE_AND_CLOSE;
+ } else {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* WE STILL HAVE MORE INFORMATION IN THIS LOG FILE. WE ONLY MOVE BACK */
+ /* THE FILE PAGE. */
+ /*---------------------------------------------------------------------------*/
+ cactiveUndoFilePage = cactiveUndoFilePage - tmp1;
+ fsConnectptr.p->fsState = READ_UNDO_PAGE;
+ }//if
+ return;
+}//Dbacc::srStartUndoLab()
+
+/* ------- DO UNDO ---------------------------*/
+/* ******************--------------------------------------------------------------- */
+/* NEXTOPERATION ORD FOR EXECUTION OF NEXT OP */
+/* ******************------------------------------+ */
+/* SENDER: ACC, LEVEL B */
+void Dbacc::execNEXTOPERATION(Signal* signal)
+{
+ jamEntry();
+ tresult = 0;
+ srDoUndoLab(signal);
+ return;
+}//Dbacc::execNEXTOPERATION()
+
+void Dbacc::srDoUndoLab(Signal* signal)
+{
+ DirRangePtr souDirRangePtr;
+ DirectoryarrayPtr souDirptr;
+ Page8Ptr souPageidptr;
+ Uint32 tundoPageindex;
+ UndoHeader *undoHeaderPtr;
+ Uint32 tmpindex;
+
+ jam();
+ undopageptr.i = cactiveSrUndoPage;
+ ptrCheckGuard(undopageptr, cundopagesize, undopage);
+ /*---------------------------------------------------------------------------*/
+ /* LAYOUT OF AN UNDO LOG RECORD: */
+ /* ***************************** */
+ /* */
+ /* |----------------------------------------------------| */
+ /* | TABLE ID | */
+ /* |----------------------------------------------------| */
+ /* | ROOT FRAGMENT ID | */
+ /* |----------------------------------------------------| */
+ /* | LOCAL FRAGMENT ID | */
+ /* |----------------------------------------------------| */
+ /* | UNDO INFO LEN 14 b | TYPE 4 b | PAGE INDEX 14 b | */
+ /* |----------------------------------------------------| */
+ /* | INDEX INTO PAGE DIRECTORY (LOGICAL PAGE ID) | */
+ /* |----------------------------------------------------| */
+ /* | PREVIOUS UNDO LOG RECORD FOR THE FRAGMENT | */
+ /* |----------------------------------------------------| */
+ /* | PREVIOUS UNDO LOG RECORD FOR ALL FRAGMENTS | */
+ /* |----------------------------------------------------| */
+ /* | TYPE SPECIFIC PART | */
+ /* |----------------------------------------------------| */
+ /*---------------------------------------------------------------------------*/
+ /*---------------------------------------------------------------------------*/
+ /* SET THE PAGE POINTER. WE ONLY WORK WITH TWO PAGES IN THIS RESTART */
+ /* ACTIVITY. GET THE PAGE POINTER AND THE PAGE INDEX TO READ FROM. */
+ /*---------------------------------------------------------------------------*/
+ tundoindex = cprevUndoaddress & ZUNDOPAGEINDEX_MASK; //0x1fff, 13 bits.
+ undoHeaderPtr = (UndoHeader *) &undopageptr.p->undoword[tundoindex];
+ tundoindex = tundoindex + ZUNDOHEADSIZE;
+
+ /*------------------------------------------------------------------------*/
+ /* READ TABLE ID AND ROOT FRAGMENT ID AND USE THIS TO GET ROOT RECORD. */
+ /*------------------------------------------------------------------------*/
+ arrGuard((tundoindex + 6), 8192);
+
+ // TABLE ID
+ tabptr.i = undoHeaderPtr->tableId;
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+
+ // ROOT FRAGMENT ID
+ tfid = undoHeaderPtr->rootFragId;
+ ndbrequire((undoHeaderPtr->localFragId >> 1) == undoHeaderPtr->rootFragId);
+ if (!getrootfragmentrec(signal, rootfragrecptr, tfid)) {
+ jam();
+ /*---------------------------------------------------------------------*/
+ /* THE ROOT RECORD WAS NOT FOUND. OBVIOUSLY WE ARE NOT RESTARTING THIS */
+ /* FRAGMENT. WE THUS IGNORE THIS LOG RECORD AND PROCEED WITH THE NEXT. */
+ /*---------------------------------------------------------------------*/
+ creadyUndoaddress = cprevUndoaddress;
+ // PREVIOUS UNDO LOG RECORD FOR ALL FRAGMENTS
+ cprevUndoaddress = undoHeaderPtr->prevUndoAddress;
+ undoNext2Lab(signal);
+#ifdef VM_TRACE
+ ndbout_c("ignoring root fid %d", (int)tfid);
+#endif
+ return;
+ }//if
+ /*-----------------------------------------------------------------------*/
+ /* READ THE LOCAL FRAGMENT ID AND VERIFY THAT IT IS CORRECT. */
+ /*-----------------------------------------------------------------------*/
+ if (rootfragrecptr.p->fragmentid[0] == undoHeaderPtr->localFragId) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ } else {
+ if (rootfragrecptr.p->fragmentid[1] == undoHeaderPtr->localFragId) {
+ jam();
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[1];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ } else {
+ jam();
+ progError(__LINE__, 0, "Invalid local fragment id in undo log");
+ return;
+ }//if
+ }//if
+ /*------------------------------------------------------------------------*/
+ /* READ UNDO INFO LENGTH, TYPE OF LOG RECORD AND PAGE INDEX WHERE TO */
+ /* APPLY THIS LOG RECORD. ALSO STEP INDEX TO PREPARE READ OF LOGICAL */
+ /* PAGE ID. SET TMPINDEX TO INDEX THE FIRST WORD IN THE TYPE SPECIFIC */
+ /* PART. */
+ /*------------------------------------------------------------------------*/
+ // UNDO INFO LENGTH 14 b | TYPE 4 b | PAGE INDEX 14 b
+ const Uint32 tmp1 = undoHeaderPtr->variousInfo;
+ cundoinfolength = tmp1 >> 18;
+ const Uint32 tpageType = (tmp1 >> 14) & 0xf;
+ tundoPageindex = tmp1 & 0x3fff;
+
+ // INDEX INTO PAGE DIRECTORY (LOGICAL PAGE ID)
+ tmpP = undoHeaderPtr->logicalPageId ;
+ tmpindex = tundoindex;
+ arrGuard((tmpindex + cundoinfolength - 1), 8192);
+ if (fragrecptr.p->localCheckpId != cactiveCheckpId) {
+ jam();
+ /*-----------------------------------------------------------------------*/
+ /* THE FRAGMENT DID EXIST BUT IS NOT AFFECTED BY THIS UNDO LOG */
+ /* EXECUTION. EITHER IT BELONGS TO ANOTHER OR IT IS CREATED AND ONLY IN */
+ /* NEED OF EXECUTION OF REDO LOG RECORDS FROM LQH. */
+ /*-----------------------------------------------------------------------*/
+ creadyUndoaddress = cprevUndoaddress;
+ // PREVIOUS UNDO LOG RECORD FOR ALL FRAGMENTS
+ cprevUndoaddress = undoHeaderPtr->prevUndoAddress;
+
+ undoNext2Lab(signal);
+ return;
+ }//if
+ /*-----------------------------------------------------------------------*/
+ /* VERIFY CONSISTENCY OF UNDO LOG RECORDS. */
+ /*-----------------------------------------------------------------------*/
+ ndbrequire(fragrecptr.p->prevUndoposition == cprevUndoaddress);
+ cSrUndoRecords[tpageType]++;
+ switch(tpageType){
+
+ case UndoHeader::ZPAGE_INFO:{
+ jam();
+ /*----------------------------------------------------------------------*/
+ /* WE HAVE TO UNDO UPDATES IN A NORMAL PAGE. GET THE PAGE POINTER BY */
+ /* USING THE LOGICAL PAGE ID. THEN RESET THE OLD VALUE IN THE PAGE BY */
+ /* USING THE OLD DATA WHICH IS STORED IN THIS UNDO LOG RECORD. */
+ /*----------------------------------------------------------------------*/
+ souDirRangePtr.i = fragrecptr.p->directory;
+ tmpP2 = tmpP >> 8;
+ tmpP = tmpP & 0xff;
+ ptrCheckGuard(souDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tmpP2, 256);
+ souDirptr.i = souDirRangePtr.p->dirArray[tmpP2];
+ ptrCheckGuard(souDirptr, cdirarraysize, directoryarray);
+ souPageidptr.i = souDirptr.p->pagep[tmpP];
+ ptrCheckGuard(souPageidptr, cpagesize, page8);
+ Uint32 loopLimit = tundoPageindex + cundoinfolength;
+ ndbrequire(loopLimit <= 2048);
+ for (Uint32 tmp = tundoPageindex; tmp < loopLimit; tmp++) {
+ dbgWord32(souPageidptr, tmp, undopageptr.p->undoword[tmpindex]);
+ souPageidptr.p->word32[tmp] = undopageptr.p->undoword[tmpindex];
+ tmpindex = tmpindex + 1;
+ }//for
+ break;
+ }
+
+ case UndoHeader::ZOVER_PAGE_INFO:{
+ jam();
+ /*----------------------------------------------------------------------*/
+ /* WE HAVE TO UNDO UPDATES IN AN OVERFLOW PAGE. GET THE PAGE POINTER BY*/
+ /* USING THE LOGICAL PAGE ID. THEN RESET THE OLD VALUE IN THE PAGE BY */
+ /* USING THE OLD DATA WHICH IS STORED IN THIS UNDO LOG RECORD. */
+ /*----------------------------------------------------------------------*/
+ souDirRangePtr.i = fragrecptr.p->overflowdir;
+ tmpP2 = tmpP >> 8;
+ tmpP = tmpP & 0xff;
+ ptrCheckGuard(souDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tmpP2, 256);
+ souDirptr.i = souDirRangePtr.p->dirArray[tmpP2];
+ ptrCheckGuard(souDirptr, cdirarraysize, directoryarray);
+ souPageidptr.i = souDirptr.p->pagep[tmpP];
+ ptrCheckGuard(souPageidptr, cpagesize, page8);
+ Uint32 loopLimit = tundoPageindex + cundoinfolength;
+ ndbrequire(loopLimit <= 2048);
+ for (Uint32 tmp = tundoPageindex; tmp < loopLimit; tmp++) {
+ dbgWord32(souPageidptr, tmp, undopageptr.p->undoword[tmpindex]);
+ souPageidptr.p->word32[tmp] = undopageptr.p->undoword[tmpindex];
+ tmpindex = tmpindex + 1;
+ }//for
+ break;
+ }
+
+ case UndoHeader::ZOP_INFO: {
+ jam();
+ /*---------------------------------------------------------------------*/
+ /* AN OPERATION WAS ACTIVE WHEN LOCAL CHECKPOINT WAS EXECUTED. WE NEED */
+ /* TO RESET THE LOCKS IT HAS SET. IF THE OPERATION WAS AN INSERT OR */
+ /* THE ELEMENT WAS MARKED AS DISSAPEARED IT WILL ALSO BE REMOVED */
+ /* FROM THE PAGE */
+ /* */
+ /* BEGIN BY SEARCHING AFTER THE ELEMENT, WHEN FOUND UNDO THE */
+ /* CHANGES ON THE ELEMENT HEADER. IF IT WAS AN INSERT OPERATION OR */
+ /* MARKED AS DISSAPEARED PROCEED BY REMOVING THE ELEMENT. */
+ /*---------------------------------------------------------------------*/
+ seizeOpRec(signal);
+ // Initialise the opRec
+ operationRecPtr.p->transId1 = 0;
+ operationRecPtr.p->transId2 = RNIL;
+ operationRecPtr.p->transactionstate = ACTIVE;
+ operationRecPtr.p->commitDeleteCheckFlag = ZFALSE;
+ operationRecPtr.p->lockMode = 0;
+ operationRecPtr.p->dirtyRead = 0;
+ operationRecPtr.p->nodeType = 0;
+ operationRecPtr.p->fid = fragrecptr.p->myfid;
+ operationRecPtr.p->nextParallelQue = RNIL;
+ operationRecPtr.p->prevParallelQue = RNIL;
+ operationRecPtr.p->nextQueOp = RNIL;
+ operationRecPtr.p->prevQueOp = RNIL;
+ operationRecPtr.p->nextSerialQue = RNIL;
+ operationRecPtr.p->prevSerialQue = RNIL;
+ operationRecPtr.p->elementPage = RNIL;
+ operationRecPtr.p->keyinfoPage = RNIL;
+ operationRecPtr.p->insertIsDone = ZFALSE;
+ operationRecPtr.p->lockOwner = ZFALSE;
+ operationRecPtr.p->elementIsDisappeared = ZFALSE;
+ operationRecPtr.p->insertDeleteLen = fragrecptr.p->elementLength;
+ operationRecPtr.p->longPagePtr = RNIL;
+ operationRecPtr.p->longKeyPageIndex = RNIL;
+ operationRecPtr.p->scanRecPtr = RNIL;
+ operationRecPtr.p->isAccLockReq = ZFALSE;
+ operationRecPtr.p->isUndoLogReq = ZTRUE;
+
+ // Read operation values from undo page
+ operationRecPtr.p->operation = undopageptr.p->undoword[tmpindex];
+ tmpindex++;
+ operationRecPtr.p->hashValue = undopageptr.p->undoword[tmpindex];
+ tmpindex++;
+ const Uint32 tkeylen = undopageptr.p->undoword[tmpindex];
+ tmpindex++;
+ operationRecPtr.p->tupkeylen = tkeylen;
+ operationRecPtr.p->xfrmtupkeylen = 0; // not used
+ operationRecPtr.p->fragptr = fragrecptr.i;
+
+ ndbrequire(fragrecptr.p->keyLength != 0 &&
+ fragrecptr.p->keyLength == tkeylen);
+
+ // Read localkey1 from undo page
+ signal->theData[7 + 0] = undopageptr.p->undoword[tmpindex];
+ tmpindex = tmpindex + 1;
+ arrGuard((tmpindex - 1), 8192);
+ getElement(signal);
+ if (tgeResult != ZTRUE) {
+ jam();
+ signal->theData[0] = RNIL;
+ signal->theData[1] = tabptr.i;
+ signal->theData[2] = cactiveCheckpId;
+ signal->theData[3] = cprevUndoaddress;
+ signal->theData[4] = operationRecPtr.p->operation;
+ signal->theData[5] = operationRecPtr.p->hashValue;
+ signal->theData[6] = operationRecPtr.p->tupkeylen;
+ sendSignal(cownBlockref, GSN_DEBUG_SIG, signal, 11, JBA);
+ return;
+ }//if
+
+ operationRecPtr.p->elementPage = gePageptr.i;
+ operationRecPtr.p->elementContainer = tgeContainerptr;
+ operationRecPtr.p->elementPointer = tgeElementptr;
+ operationRecPtr.p->elementIsforward = tgeForward;
+
+ commitdelete(signal, true);
+ releaseOpRec(signal);
+ break;
+ }
+
+ default:
+ jam();
+ progError(__LINE__, 0, "Invalid pagetype in undo log");
+ break;
+
+ }//switch(tpageType)
+
+ /*----------------------------------------------------------------------*/
+ /* READ THE PAGE ID AND THE PAGE INDEX OF THE PREVIOUS UNDO LOG RECORD */
+ /* FOR THIS FRAGMENT. */
+ /*----------------------------------------------------------------------*/
+ fragrecptr.p->prevUndoposition = undoHeaderPtr->prevUndoAddressForThisFrag;
+ /*----------------------------------------------------------------------*/
+ /* READ THE PAGE ID AND THE PAGE INDEX OF THE PREVIOUS UNDO LOG RECORD */
+ /* FOR THIS UNDO LOG. */
+ /*----------------------------------------------------------------------*/
+ creadyUndoaddress = cprevUndoaddress;
+ cprevUndoaddress = undoHeaderPtr->prevUndoAddress;
+
+ if (fragrecptr.p->prevUndoposition == cminusOne) {
+ jam();
+ /*---------------------------------------------------------------------*/
+ /* WE HAVE NOW EXECUTED ALL UNDO LOG RECORDS FOR THIS FRAGMENT. WE */
+ /* NOW NEED TO UPDATE THE FREE LIST OF OVERFLOW PAGES. */
+ /*---------------------------------------------------------------------*/
+ ndbrequire(fragrecptr.p->nextAllocPage == 0);
+
+ signal->theData[0] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_OVER_REC, signal, 1, JBB);
+ return;
+ }//if
+ undoNext2Lab(signal);
+ return;
+}//Dbacc::srDoUndoLab()
+
+void Dbacc::undoNext2Lab(Signal* signal)
+{
+ /*---------------------------------------------------------------------------*/
+ /* EXECUTE NEXT UNDO LOG RECORD. */
+ /*---------------------------------------------------------------------------*/
+ if (cprevUndoaddress == cminusOne) {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* WE HAVE EXECUTED THIS UNDO LOG TO COMPLETION. IT IS NOW TIME TO TAKE*/
+ /* OF THE NEXT UNDO LOG OR REPORT COMPLETION OF UNDO LOG EXECUTION. */
+ /*---------------------------------------------------------------------------*/
+ signal->theData[0] = ZSTART_UNDO;
+ sendSignal(cownBlockref, GSN_CONTINUEB, signal, 1, JBB);
+ return;
+ }//if
+ if ((creadyUndoaddress >> 13) != (cprevUndoaddress >> 13)) {
+ /*---------------------------------------------------------------------------*/
+ /* WE ARE CHANGING PAGE. */
+ /*---------------------------------------------------------------------------*/
+ if (cactiveSrUndoPage == 0) {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* WE HAVE READ AND EXECUTED ALL UNDO LOG INFORMATION IN THE CURRENTLY */
+ /* READ PAGES. WE STILL HAVE MORE INFORMATION TO READ FROM FILE SINCE */
+ /* WE HAVEN'T FOUND THE FIRST LOG RECORD IN THE LOG FILE YET. */
+ /*---------------------------------------------------------------------------*/
+ srStartUndoLab(signal);
+ return;
+ } else {
+ jam();
+ /*---------------------------------------------------------------------------*/
+ /* WE HAVE ANOTHER PAGE READ THAT WE NEED TO EXECUTE. */
+ /*---------------------------------------------------------------------------*/
+ cactiveSrUndoPage = cactiveSrUndoPage - 1;
+ }//if
+ }//if
+ /*---------------------------------------------------------------------------*/
+ /* REAL-TIME BREAK */
+ /*---------------------------------------------------------------------------*/
+ /* ******************************< */
+ /* NEXTOPERATION */
+ /* ******************************< */
+ sendSignal(cownBlockref, GSN_NEXTOPERATION, signal, 1, JBB);
+ return;
+}//Dbacc::undoNext2Lab()
+
+/*-----------------------------------------------------------------------------------*/
+/* AFTER COMPLETING THE READING OF DATA PAGES FROM DISK AND EXECUTING THE UNDO */
+/* LOG WE ARE READY TO UPDATE THE FREE LIST OF OVERFLOW PAGES. THIS LIST MUST */
+/* BE BUILT AGAIN SINCE IT IS NOT CHECKPOINTED. WHEN THE PAGES ARE ALLOCATED */
+/* THEY ARE NOT PART OF ANY LIST. PAGES CAN EITHER BE PUT IN FREE LIST, NOT */
+/* IN FREE LIST OR BE PUT INTO LIST OF LONG KEY PAGES. */
+/*-----------------------------------------------------------------------------------*/
+void Dbacc::execACC_OVER_REC(Signal* signal)
+{
+ DirRangePtr pnoDirRangePtr;
+ DirectoryarrayPtr pnoOverflowDirptr;
+ Page8Ptr pnoPageidptr;
+ Uint32 tpnoPageType;
+ Uint32 toverPageCheck;
+
+ jamEntry();
+ fragrecptr.i = signal->theData[0];
+ toverPageCheck = 0;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ ndbrequire((fragrecptr.p->nextAllocPage != 0) ||
+ (fragrecptr.p->firstOverflowRec == RNIL));
+ /*-----------------------------------------------------------------------------------*/
+ /* WHO HAS PUT SOMETHING INTO THE LIST BEFORE WE EVEN STARTED PUTTING THINGS */
+ /* THERE. */
+ /*-----------------------------------------------------------------------------------*/
+ ndbrequire(fragrecptr.p->loadingFlag == ZTRUE);
+ /*---------------------------------------------------------------------------*/
+ /* LOADING HAS STOPPED BEFORE WE HAVE LOADED, SYSTEM ERROR. */
+ /*---------------------------------------------------------------------------*/
+ while (toverPageCheck < ZNO_OF_OP_PER_SIGNAL) {
+ jam();
+ if (fragrecptr.p->nextAllocPage >= fragrecptr.p->lastOverIndex) {
+ jam();
+ fragrecptr.p->loadingFlag = ZFALSE;
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (rootfragrecptr.p->lcpPtr != RNIL) {
+ jam();
+ srCloseDataFileLab(signal);
+ } else {
+ jam();
+ undoNext2Lab(signal);
+ }//if
+ return;
+ }//if
+ tmpP = fragrecptr.p->nextAllocPage;
+ pnoDirRangePtr.i = fragrecptr.p->overflowdir;
+ tmpP2 = tmpP >> 8;
+ tmpP = tmpP & 0xff;
+ arrGuard(tmpP2, 256);
+ ptrCheckGuard(pnoDirRangePtr, cdirrangesize, dirRange);
+ if (pnoDirRangePtr.p->dirArray[tmpP2] == RNIL) {
+ jam();
+ pnoPageidptr.i = RNIL;
+ } else {
+ pnoOverflowDirptr.i = pnoDirRangePtr.p->dirArray[tmpP2];
+ if (pnoOverflowDirptr.i == RNIL) {
+ jam();
+ pnoPageidptr.i = RNIL;
+ } else {
+ jam();
+ ptrCheckGuard(pnoOverflowDirptr, cdirarraysize, directoryarray);
+ pnoPageidptr.i = pnoOverflowDirptr.p->pagep[tmpP];
+ }//if
+ }//if
+ if (pnoPageidptr.i == RNIL) {
+ jam();
+ seizeOverRec(signal);
+ sorOverflowRecPtr.p->dirindex = fragrecptr.p->nextAllocPage;
+ sorOverflowRecPtr.p->overpage = RNIL;
+ priOverflowRecPtr = sorOverflowRecPtr;
+ putRecInFreeOverdir(signal);
+ } else {
+ ptrCheckGuard(pnoPageidptr, cpagesize, page8);
+ tpnoPageType = pnoPageidptr.p->word32[ZPOS_PAGE_TYPE];
+ tpnoPageType = (tpnoPageType >> ZPOS_PAGE_TYPE_BIT) & 3;
+ if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] > ZFREE_LIMIT) {
+ jam();
+ dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, RNIL);
+ pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+ ndbrequire(pnoPageidptr.p->word32[ZPOS_PAGE_ID] == fragrecptr.p->nextAllocPage);
+ } else {
+ jam();
+ seizeOverRec(signal);
+ sorOverflowRecPtr.p->dirindex = pnoPageidptr.p->word32[ZPOS_PAGE_ID];
+ ndbrequire(sorOverflowRecPtr.p->dirindex == fragrecptr.p->nextAllocPage);
+ dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, sorOverflowRecPtr.i);
+ pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = sorOverflowRecPtr.i;
+ sorOverflowRecPtr.p->overpage = pnoPageidptr.i;
+ porOverflowRecPtr = sorOverflowRecPtr;
+ putOverflowRecInFrag(signal);
+ if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] == 0) {
+ jam();
+ ropPageptr = pnoPageidptr;
+ releaseOverpage(signal);
+ }//if
+ }//if
+ }//if
+ fragrecptr.p->nextAllocPage++;
+ toverPageCheck++;
+ }//while
+ signal->theData[0] = fragrecptr.i;
+ sendSignal(cownBlockref, GSN_ACC_OVER_REC, signal, 1, JBB);
+}//Dbacc::execACC_OVER_REC()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF SYSTEM RESTART MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* SCAN MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_SCANREQ START OF A SCAN PROCESS */
+/* SENDER: LQH, LEVEL B */
+/* ENTER ACC_SCANREQ WITH */
+/* TUSERPTR, LQH SCAN_CONNECT POINTER */
+/* TUSERBLOCKREF, LQH BLOCK REFERENCE */
+/* TABPTR, TABLE IDENTITY AND PTR */
+/* TFID ROOT FRAGMENT IDENTITY */
+/* TSCAN_FLAG , = ZCOPY, ZSCAN, ZSCAN_LOCK_ALL */
+/* ZREADLOCK, ZWRITELOCK */
+/* TSCAN_TRID1 , TRANSACTION ID PART 1 */
+/* TSCAN_TRID2 TRANSACTION ID PART 2 */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_SCANREQ START OF A SCAN PROCESS */
+/* ******************------------------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACC_SCANREQ(Signal* signal)
+{
+ jamEntry();
+ AccScanReq * req = (AccScanReq*)&signal->theData[0];
+ tuserptr = req->senderData;
+ tuserblockref = req->senderRef;
+ tabptr.i = req->tableId;
+ tfid = req->fragmentNo;
+ tscanFlag = req->requestInfo;
+ tscanTrid1 = req->transId1;
+ tscanTrid2 = req->transId2;
+
+ tresult = 0;
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ ndbrequire(getrootfragmentrec(signal,rootfragrecptr, tfid));
+
+ Uint32 i;
+ for (i = 0; i < MAX_PARALLEL_SCANS_PER_FRAG; i++) {
+ jam();
+ if (rootfragrecptr.p->scan[i] == RNIL) {
+ jam();
+ break;
+ }
+ }
+ ndbrequire(i != MAX_PARALLEL_SCANS_PER_FRAG);
+ ndbrequire(cfirstFreeScanRec != RNIL);
+ seizeScanRec(signal);
+
+ rootfragrecptr.p->scan[i] = scanPtr.i;
+ scanPtr.p->scanBucketState = ScanRec::FIRST_LAP;
+ scanPtr.p->scanLockMode = AccScanReq::getLockMode(tscanFlag);
+ scanPtr.p->scanReadCommittedFlag = AccScanReq::getReadCommittedFlag(tscanFlag);
+
+ /* TWELVE BITS OF THE ELEMENT HEAD ARE SCAN */
+ /* CHECK BITS. THE MASK NOTES WHICH BIT IS */
+ /* ALLOCATED FOR THE ACTIVE SCAN */
+ scanPtr.p->scanMask = 1 << i;
+ scanPtr.p->scanUserptr = tuserptr;
+ scanPtr.p->scanUserblockref = tuserblockref;
+ scanPtr.p->scanTrid1 = tscanTrid1;
+ scanPtr.p->scanTrid2 = tscanTrid2;
+ scanPtr.p->rootPtr = rootfragrecptr.i;
+ scanPtr.p->scanLockHeld = 0;
+ scanPtr.p->scanOpsAllocated = 0;
+ scanPtr.p->scanFirstActiveOp = RNIL;
+ scanPtr.p->scanFirstQueuedOp = RNIL;
+ scanPtr.p->scanLastQueuedOp = RNIL;
+ scanPtr.p->scanFirstLockedOp = RNIL;
+ scanPtr.p->scanLastLockedOp = RNIL;
+ scanPtr.p->scanState = ScanRec::WAIT_NEXT;
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[0];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ initScanFragmentPart(signal);
+
+ /*------------------------------------------------------*/
+ /* We start the timeout loop for the scan process here. */
+ /*------------------------------------------------------*/
+ ndbrequire(scanPtr.p->scanTimer == 0);
+ if (scanPtr.p->scanContinuebCounter == 0) {
+ jam();
+ scanPtr.p->scanContinuebCounter = 1;
+ signal->theData[0] = ZSEND_SCAN_HBREP;
+ signal->theData[1] = scanPtr.i;
+ sendSignalWithDelay(cownBlockref, GSN_CONTINUEB, signal, 100, 2);
+ }//if
+ scanPtr.p->scanTimer = scanPtr.p->scanContinuebCounter;
+ /* ************************ */
+ /* ACC_SCANCONF */
+ /* ************************ */
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = scanPtr.i;
+ signal->theData[2] = 2;
+ /* NR OF LOCAL FRAGMENT */
+ signal->theData[3] = rootfragrecptr.p->fragmentid[0];
+ signal->theData[4] = rootfragrecptr.p->fragmentid[1];
+ signal->theData[7] = AccScanConf::ZNOT_EMPTY_FRAGMENT;
+ sendSignal(scanPtr.p->scanUserblockref, GSN_ACC_SCANCONF, signal, 8, JBB);
+ /* NOT EMPTY FRAGMENT */
+ return;
+}//Dbacc::execACC_SCANREQ()
+
+/* ******************--------------------------------------------------------------- */
+/* NEXT_SCANREQ REQUEST FOR NEXT ELEMENT OF */
+/* ******************------------------------------+ A FRAGMENT. */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execNEXT_SCANREQ(Signal* signal)
+{
+ Uint32 tscanNextFlag;
+ jamEntry();
+ scanPtr.i = signal->theData[0];
+ operationRecPtr.i = signal->theData[1];
+ tscanNextFlag = signal->theData[2];
+ /* ------------------------------------------ */
+ /* 1 = ZCOPY_NEXT GET NEXT ELEMENT */
+ /* 2 = ZCOPY_NEXT_COMMIT COMMIT THE */
+ /* ACTIVE ELEMENT AND GET THE NEXT ONE */
+ /* 3 = ZCOPY_COMMIT COMMIT THE ACTIVE ELEMENT */
+ /* 4 = ZCOPY_REPEAT GET THE ACTIVE ELEMENT */
+ /* 5 = ZCOPY_ABORT RELOCK THE ACTIVE ELEMENT */
+ /* 6 = ZCOPY_CLOSE THE SCAN PROCESS IS READY */
+ /* ------------------------------------------ */
+ tresult = 0;
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+ ndbrequire(scanPtr.p->scanState == ScanRec::WAIT_NEXT);
+
+ scanPtr.p->scanTimer = scanPtr.p->scanContinuebCounter;
+ switch (tscanNextFlag) {
+ case ZCOPY_NEXT:
+ jam();
+ /*empty*/;
+ break;
+ case ZCOPY_NEXT_COMMIT:
+ case ZCOPY_COMMIT:
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* COMMIT ACTIVE OPERATION. SEND NEXT SCAN ELEMENT IF IT IS ZCOPY_NEXT_COMMIT. */
+ /* --------------------------------------------------------------------------------- */
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_COMMIT) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // We did not have enough undo log buffers to safely commit an
+ // operation. Try again in 10 milliseconds.
+ /*--------------------------------------------------------------*/
+ sendSignalWithDelay(cownBlockref, GSN_NEXT_SCANREQ, signal, 10, 3);
+ return;
+ }//if
+ }//if
+ commitOperation(signal);
+ }//if
+ takeOutActiveScanOp(signal);
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ if (tscanNextFlag == ZCOPY_COMMIT) {
+ jam();
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ Uint32 blockNo = refToBlock(scanPtr.p->scanUserblockref);
+ EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 1);
+ return;
+ }//if
+ break;
+ case ZCOPY_CLOSE:
+ jam();
+ fragrecptr.i = scanPtr.p->activeLocalFrag;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_OPERATION) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // We did not have enough undo log buffers to commit a set of
+ // operations. Try again in 10 milliseconds.
+ /*--------------------------------------------------------------*/
+ sendSignalWithDelay(cownBlockref, GSN_NEXT_SCANREQ, signal, 10, 3);
+ return;
+ }//if
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* THE SCAN PROCESS IS FINISHED. RELOCK ALL LOCKED EL. RELESE ALL INVOLVED REC. */
+ /* --------------------------------------------------------------------------------- */
+ releaseScanLab(signal);
+ return;
+ break;
+ default:
+ ndbrequire(false);
+ break;
+ }//switch
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZNOT_CHECK_LCP_STOP;
+ execACC_CHECK_SCAN(signal);
+ return;
+}//Dbacc::execNEXT_SCANREQ()
+
+void Dbacc::checkNextBucketLab(Signal* signal)
+{
+ DirRangePtr cscDirRangePtr;
+ DirectoryarrayPtr cscDirptr;
+ DirectoryarrayPtr tnsDirptr;
+ Page8Ptr nsPageptr;
+ Page8Ptr cscPageidptr;
+ Page8Ptr gnsPageidptr;
+ Page8Ptr tnsPageidptr;
+ Uint32 tnsElementptr;
+ Uint32 tnsContainerptr;
+ Uint32 tnsIsLocked;
+ Uint32 tnsTmp1;
+ Uint32 tnsTmp2;
+ Uint32 tnsCopyIndex1;
+ Uint32 tnsCopyIndex2;
+ Uint32 tnsCopyDir;
+
+ tnsCopyDir = scanPtr.p->nextBucketIndex >> fragrecptr.p->k;
+ tnsCopyIndex1 = tnsCopyDir >> 8;
+ tnsCopyIndex2 = tnsCopyDir & 0xff;
+ arrGuard(tnsCopyIndex1, 256);
+ tnsDirptr.i = gnsDirRangePtr.p->dirArray[tnsCopyIndex1];
+ ptrCheckGuard(tnsDirptr, cdirarraysize, directoryarray);
+ tnsPageidptr.i = tnsDirptr.p->pagep[tnsCopyIndex2];
+ ptrCheckGuard(tnsPageidptr, cpagesize, page8);
+ gnsPageidptr.i = tnsPageidptr.i;
+ gnsPageidptr.p = tnsPageidptr.p;
+ tnsTmp1 = (1 << fragrecptr.p->k) - 1;
+ tgsePageindex = scanPtr.p->nextBucketIndex & tnsTmp1;
+ gsePageidptr.i = gnsPageidptr.i;
+ gsePageidptr.p = gnsPageidptr.p;
+ if (!getScanElement(signal)) {
+ scanPtr.p->nextBucketIndex++;
+ if (scanPtr.p->scanBucketState == ScanRec::SECOND_LAP) {
+ if (scanPtr.p->nextBucketIndex > scanPtr.p->maxBucketIndexToRescan) {
+ /* --------------------------------------------------------------------------------- */
+ // We have finished the rescan phase. We are ready to proceed with the next fragment part.
+ /* --------------------------------------------------------------------------------- */
+ jam();
+ checkNextFragmentLab(signal);
+ return;
+ }//if
+ } else if (scanPtr.p->scanBucketState == ScanRec::FIRST_LAP) {
+ if ((fragrecptr.p->p + fragrecptr.p->maxp) < scanPtr.p->nextBucketIndex) {
+ /* --------------------------------------------------------------------------------- */
+ // All buckets have been scanned a first time.
+ /* --------------------------------------------------------------------------------- */
+ if (scanPtr.p->minBucketIndexToRescan == 0xFFFFFFFF) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // We have not had any merges behind the scan. Thus it is not necessary to perform
+ // any rescan any buckets and we can proceed immediately with the next fragment part.
+ /* --------------------------------------------------------------------------------- */
+ checkNextFragmentLab(signal);
+ return;
+ } else {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // Some buckets are in the need of rescanning due to merges that have moved records
+ // from in front of the scan to behind the scan. During the merges we kept track of
+ // which buckets that need a rescan. We start with the minimum and end with maximum.
+ /* --------------------------------------------------------------------------------- */
+ scanPtr.p->nextBucketIndex = scanPtr.p->minBucketIndexToRescan;
+ scanPtr.p->scanBucketState = ScanRec::SECOND_LAP;
+ if (scanPtr.p->maxBucketIndexToRescan > (fragrecptr.p->p + fragrecptr.p->maxp)) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // If we have had so many merges that the maximum is bigger than the number of buckets
+ // then we will simply satisfy ourselves with scanning to the end. This can only happen
+ // after bringing down the total of buckets to less than half and the minimum should
+ // be 0 otherwise there is some problem.
+ /* --------------------------------------------------------------------------------- */
+ if (scanPtr.p->minBucketIndexToRescan != 0) {
+ jam();
+ sendSystemerror(signal);
+ return;
+ }//if
+ scanPtr.p->maxBucketIndexToRescan = fragrecptr.p->p + fragrecptr.p->maxp;
+ }//if
+ }//if
+ }//if
+ }//if
+ if ((scanPtr.p->scanBucketState == ScanRec::FIRST_LAP) &&
+ (scanPtr.p->nextBucketIndex <= scanPtr.p->startNoOfBuckets)) {
+ /* --------------------------------------------------------------------------------- */
+ // We will only reset the scan indicator on the buckets that existed at the start of the
+ // scan. The others will be handled by the split and merge code.
+ /* --------------------------------------------------------------------------------- */
+ tnsTmp2 = (1 << fragrecptr.p->k) - 1;
+ trsbPageindex = scanPtr.p->nextBucketIndex & tnsTmp2;
+ if (trsbPageindex != 0) {
+ jam();
+ rsbPageidptr.i = gnsPageidptr.i;
+ rsbPageidptr.p = gnsPageidptr.p;
+ } else {
+ jam();
+ cscDirRangePtr.i = fragrecptr.p->directory;
+ tmpP = scanPtr.p->nextBucketIndex >> fragrecptr.p->k;
+ tmpP2 = tmpP >> 8;
+ tmpP = tmpP & 0xff;
+ ptrCheckGuard(cscDirRangePtr, cdirrangesize, dirRange);
+ arrGuard(tmpP2, 256);
+ cscDirptr.i = cscDirRangePtr.p->dirArray[tmpP2];
+ ptrCheckGuard(cscDirptr, cdirarraysize, directoryarray);
+ cscPageidptr.i = cscDirptr.p->pagep[tmpP];
+ ptrCheckGuard(cscPageidptr, cpagesize, page8);
+ tmp1 = (1 << fragrecptr.p->k) - 1;
+ trsbPageindex = scanPtr.p->nextBucketIndex & tmp1;
+ rsbPageidptr.i = cscPageidptr.i;
+ rsbPageidptr.p = cscPageidptr.p;
+ }//if
+ releaseScanBucket(signal);
+ }//if
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ sendSignal(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
+ return;
+ }//if
+ /* ----------------------------------------------------------------------- */
+ /* AN ELEMENT WHICH HAVE NOT BEEN SCANNED WAS FOUND. WE WILL PREPARE IT */
+ /* TO BE SENT TO THE LQH BLOCK FOR FURTHER PROCESSING. */
+ /* WE ASSUME THERE ARE OPERATION RECORDS AVAILABLE SINCE LQH SHOULD HAVE*/
+ /* GUARANTEED THAT THROUGH EARLY BOOKING. */
+ /* ----------------------------------------------------------------------- */
+ tnsIsLocked = tgseIsLocked;
+ tnsElementptr = tgseElementptr;
+ tnsContainerptr = tgseContainerptr;
+ nsPageptr.i = gsePageidptr.i;
+ nsPageptr.p = gsePageidptr.p;
+ seizeOpRec(signal);
+ tisoIsforward = tgseIsforward;
+ tisoContainerptr = tnsContainerptr;
+ tisoElementptr = tnsElementptr;
+ isoPageptr.i = nsPageptr.i;
+ isoPageptr.p = nsPageptr.p;
+ initScanOpRec(signal);
+
+ if (!tnsIsLocked){
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ jam();
+ slPageidptr = nsPageptr;
+ tslElementptr = tnsElementptr;
+ setlock(signal);
+ insertLockOwnersList(signal, operationRecPtr);
+ }//if
+ } else {
+ arrGuard(tnsElementptr, 2048);
+ queOperPtr.i =
+ ElementHeader::getOpPtrI(nsPageptr.p->word32[tnsElementptr]);
+ ptrCheckGuard(queOperPtr, coprecsize, operationrec);
+ if (queOperPtr.p->elementIsDisappeared == ZTRUE) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // If the lock owner indicates the element is disappeared then we will not report this
+ // tuple. We will continue with the next tuple.
+ /* --------------------------------------------------------------------------------- */
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ sendSignal(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
+ return;
+ }//if
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ Uint32 return_result;
+ if (scanPtr.p->scanLockMode == ZREADLOCK) {
+ jam();
+ priPageptr = nsPageptr;
+ tpriElementptr = tnsElementptr;
+ return_result = placeReadInLockQueue(signal);
+ } else {
+ jam();
+ pwiPageptr = nsPageptr;
+ tpwiElementptr = tnsElementptr;
+ return_result = placeWriteInLockQueue(signal);
+ }//if
+ if (return_result == ZSERIAL_QUEUE) {
+ /* --------------------------------------------------------------------------------- */
+ /* WE PLACED THE OPERATION INTO A SERIAL QUEUE AND THUS WE HAVE TO WAIT FOR */
+ /* THE LOCK TO BE RELEASED. WE CONTINUE WITH THE NEXT ELEMENT. */
+ /* --------------------------------------------------------------------------------- */
+ putOpScanLockQue(); /* PUT THE OP IN A QUE IN THE SCAN REC */
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ sendSignal(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
+ return;
+ } else if (return_result == ZWRITE_ERROR) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // The tuple is either not committed yet or a delete in the same transaction (not
+ // possible here since we are a scan). Thus we simply continue with the next tuple.
+ /* --------------------------------------------------------------------------------- */
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ sendSignal(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
+ return;
+ }//if
+ ndbassert(return_result == ZPARALLEL_QUEUE);
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ // Committed read proceed without caring for locks immediately down here except when
+ // the tuple was deleted permanently and no new operation has inserted it again.
+ /* --------------------------------------------------------------------------------- */
+ putActiveScanOp(signal);
+ sendNextScanConf(signal);
+ return;
+}//Dbacc::checkNextBucketLab()
+
+
+void Dbacc::checkNextFragmentLab(Signal* signal)
+{
+ RootfragmentrecPtr cnfRootfragrecptr;
+
+ cnfRootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(cnfRootfragrecptr, crootfragmentsize, rootfragmentrec);
+ if (scanPtr.p->activeLocalFrag == cnfRootfragrecptr.p->fragmentptr[0]) {
+ jam();
+ fragrecptr.i = cnfRootfragrecptr.p->fragmentptr[1];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ initScanFragmentPart(signal);
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ sendSignal(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 2, JBB);
+ return;
+ } else {
+ if (scanPtr.p->activeLocalFrag == cnfRootfragrecptr.p->fragmentptr[1]) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ // Both fragments have completed their scan part and we can indicate that the scan is
+ // now completed.
+ /* --------------------------------------------------------------------------------- */
+ scanPtr.p->scanBucketState = ScanRec::SCAN_COMPLETED;
+ /*empty*/;
+ } else {
+ jam();
+ /* ALL ELEMENTS ARE SENT */
+ sendSystemerror(signal);
+ }//if
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ // The scan is completed. ACC_CHECK_SCAN will perform all the necessary checks to see
+ // what the next step is.
+ /* --------------------------------------------------------------------------------- */
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ execACC_CHECK_SCAN(signal);
+ return;
+}//Dbacc::checkNextFragmentLab()
+
+void Dbacc::initScanFragmentPart(Signal* signal)
+{
+ DirRangePtr cnfDirRangePtr;
+ DirectoryarrayPtr cnfDirptr;
+ Page8Ptr cnfPageidptr;
+ /* --------------------------------------------------------------------------------- */
+ // Set the active fragment part.
+ // Set the current bucket scanned to the first.
+ // Start with the first lap.
+ // Remember the number of buckets at start of the scan.
+ // Set the minimum and maximum to values that will always be smaller and larger than.
+ // Reset the scan indicator on the first bucket.
+ /* --------------------------------------------------------------------------------- */
+ scanPtr.p->activeLocalFrag = fragrecptr.i;
+ scanPtr.p->nextBucketIndex = 0; /* INDEX OF SCAN BUCKET */
+ scanPtr.p->scanBucketState = ScanRec::FIRST_LAP;
+ scanPtr.p->startNoOfBuckets = fragrecptr.p->p + fragrecptr.p->maxp;
+ scanPtr.p->minBucketIndexToRescan = 0xFFFFFFFF;
+ scanPtr.p->maxBucketIndexToRescan = 0;
+ cnfDirRangePtr.i = fragrecptr.p->directory;
+ ptrCheckGuard(cnfDirRangePtr, cdirrangesize, dirRange);
+ cnfDirptr.i = cnfDirRangePtr.p->dirArray[0];
+ ptrCheckGuard(cnfDirptr, cdirarraysize, directoryarray);
+ cnfPageidptr.i = cnfDirptr.p->pagep[0];
+ ptrCheckGuard(cnfPageidptr, cpagesize, page8);
+ trsbPageindex = scanPtr.p->nextBucketIndex & ((1 << fragrecptr.p->k) - 1);
+ rsbPageidptr.i = cnfPageidptr.i;
+ rsbPageidptr.p = cnfPageidptr.p;
+ releaseScanBucket(signal);
+}//Dbacc::initScanFragmentPart()
+
+/* --------------------------------------------------------------------------------- */
+/* FLAG = 6 = ZCOPY_CLOSE THE SCAN PROCESS IS READY OR ABORTED. ALL OPERATION IN THE */
+/* ACTIVE OR WAIT QUEUE ARE RELEASED, SCAN FLAG OF ROOT FRAG IS RESET AND THE SCAN */
+/* RECORD IS RELEASED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseScanLab(Signal* signal)
+{
+ releaseAndCommitActiveOps(signal);
+ releaseAndCommitQueuedOps(signal);
+ releaseAndAbortLockedOps(signal);
+
+ rootfragrecptr.i = scanPtr.p->rootPtr;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ for (tmp = 0; tmp < MAX_PARALLEL_SCANS_PER_FRAG; tmp++) {
+ jam();
+ if (rootfragrecptr.p->scan[tmp] == scanPtr.i) {
+ jam();
+ rootfragrecptr.p->scan[tmp] = RNIL;
+ }//if
+ }//for
+ // Stops the heartbeat.
+ scanPtr.p->scanTimer = 0;
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = RNIL;
+ signal->theData[2] = RNIL;
+ sendSignal(scanPtr.p->scanUserblockref, GSN_NEXT_SCANCONF, signal, 3, JBB);
+ releaseScanRec(signal);
+ return;
+}//Dbacc::releaseScanLab()
+
+
+void Dbacc::releaseAndCommitActiveOps(Signal* signal)
+{
+ OperationrecPtr trsoOperPtr;
+ operationRecPtr.i = scanPtr.p->scanFirstActiveOp;
+ while (operationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ trsoOperPtr.i = operationRecPtr.p->nextOp;
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ jam();
+ commitOperation(signal);
+ }//if
+ takeOutActiveScanOp(signal);
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ operationRecPtr.i = trsoOperPtr.i;
+ }//if
+}//Dbacc::releaseAndCommitActiveOps()
+
+
+void Dbacc::releaseAndCommitQueuedOps(Signal* signal)
+{
+ OperationrecPtr trsoOperPtr;
+ operationRecPtr.i = scanPtr.p->scanFirstQueuedOp;
+ while (operationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ trsoOperPtr.i = operationRecPtr.p->nextOp;
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ jam();
+ commitOperation(signal);
+ }//if
+ takeOutReadyScanQueue(signal);
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ operationRecPtr.i = trsoOperPtr.i;
+ }//if
+}//Dbacc::releaseAndCommitQueuedOps()
+
+void Dbacc::releaseAndAbortLockedOps(Signal* signal) {
+
+ OperationrecPtr trsoOperPtr;
+ operationRecPtr.i = scanPtr.p->scanFirstLockedOp;
+ while (operationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ trsoOperPtr.i = operationRecPtr.p->nextOp;
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (!scanPtr.p->scanReadCommittedFlag) {
+ jam();
+ abortOperation(signal);
+ }//if
+ takeOutScanLockQueue(scanPtr.i);
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ operationRecPtr.i = trsoOperPtr.i;
+ }//if
+}//Dbacc::releaseAndAbortLockedOps()
+
+/* 3.18.3 ACC_CHECK_SCAN */
+/* ******************--------------------------------------------------------------- */
+/* ACC_CHECK_SCAN */
+/* ENTER ACC_CHECK_SCAN WITH */
+/* SCAN_PTR */
+/* ******************--------------------------------------------------------------- */
+/* ******************--------------------------------------------------------------- */
+/* ACC_CHECK_SCAN */
+/* ******************------------------------------+ */
+void Dbacc::execACC_CHECK_SCAN(Signal* signal)
+{
+ Uint32 TcheckLcpStop;
+ jamEntry();
+ scanPtr.i = signal->theData[0];
+ TcheckLcpStop = signal->theData[1];
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+ while (scanPtr.p->scanFirstQueuedOp != RNIL) {
+ jam();
+ //----------------------------------------------------------------------------
+ // An operation has been released from the lock queue. We are in the parallel
+ // queue of this tuple. We are ready to report the tuple now.
+ //----------------------------------------------------------------------------
+ operationRecPtr.i = scanPtr.p->scanFirstQueuedOp;
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ takeOutReadyScanQueue(signal);
+ if (operationRecPtr.p->elementIsDisappeared == ZTRUE) {
+ jam();
+ fragrecptr.i = operationRecPtr.p->fragptr;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ if (fragrecptr.p->createLcp == ZTRUE) {
+ if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_COMMIT) {
+ jam();
+ /*--------------------------------------------------------------*/
+ // We did not have enough undo log buffers to safely abort an
+ // operation. Try again in 10 milliseconds.
+ /*--------------------------------------------------------------*/
+ sendSignalWithDelay(cownBlockref, GSN_ACC_CHECK_SCAN, signal, 10, 2);
+ return;
+ }//if
+ }//if
+ abortOperation(signal);
+ releaseOpRec(signal);
+ scanPtr.p->scanOpsAllocated--;
+ continue;
+ }//if
+ putActiveScanOp(signal);
+ sendNextScanConf(signal);
+ return;
+ }//while
+
+
+ if ((scanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED) &&
+ (scanPtr.p->scanLockHeld == 0)) {
+ jam();
+ //----------------------------------------------------------------------------
+ // The scan is now completed and there are no more locks outstanding. Thus we
+ // we will report the scan as completed to LQH.
+ //----------------------------------------------------------------------------
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = RNIL;
+ signal->theData[2] = RNIL;
+ sendSignal(scanPtr.p->scanUserblockref, GSN_NEXT_SCANCONF, signal, 3, JBB);
+ return;
+ }//if
+ if (TcheckLcpStop == AccCheckScan::ZCHECK_LCP_STOP) {
+ //---------------------------------------------------------------------------
+ // To ensure that the block of the fragment occurring at the start of a local
+ // checkpoint is not held for too long we insert a release and reacquiring of
+ // that lock here. This is performed in LQH. If we are blocked or if we have
+ // requested a sleep then we will receive RNIL in the returning signal word.
+ //---------------------------------------------------------------------------
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] =
+ ((scanPtr.p->scanLockHeld >= ZSCAN_MAX_LOCK) ||
+ (scanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED));
+ EXECUTE_DIRECT(DBLQH, GSN_CHECK_LCP_STOP, signal, 2);
+ jamEntry();
+ if (signal->theData[0] == RNIL) {
+ jam();
+ return;
+ }//if
+ }//if
+ /**
+ * If we have more than max locks held OR
+ * scan is completed AND at least one lock held
+ * - Inform LQH about this condition
+ */
+ if ((scanPtr.p->scanLockHeld >= ZSCAN_MAX_LOCK) ||
+ (cfreeopRec == RNIL) ||
+ ((scanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED) &&
+ (scanPtr.p->scanLockHeld > 0))) {
+ jam();
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = RNIL; // No operation is returned
+ signal->theData[2] = 512; // MASV
+ sendSignal(scanPtr.p->scanUserblockref, GSN_NEXT_SCANCONF, signal, 3, JBB);
+ return;
+ }
+ if (scanPtr.p->scanBucketState == ScanRec::SCAN_COMPLETED) {
+ jam();
+ signal->theData[0] = scanPtr.i;
+ signal->theData[1] = AccCheckScan::ZCHECK_LCP_STOP;
+ execACC_CHECK_SCAN(signal);
+ return;
+ }//if
+
+ scanPtr.p->scanTimer = scanPtr.p->scanContinuebCounter;
+
+ fragrecptr.i = scanPtr.p->activeLocalFrag;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ gnsDirRangePtr.i = fragrecptr.p->directory;
+ ptrCheckGuard(gnsDirRangePtr, cdirrangesize, dirRange);
+ checkNextBucketLab(signal);
+ return;
+}//Dbacc::execACC_CHECK_SCAN()
+
+/* ******************---------------------------------------------------- */
+/* ACC_TO_REQ PERFORM A TAKE OVER */
+/* ******************-------------------+ */
+/* SENDER: LQH, LEVEL B */
+void Dbacc::execACC_TO_REQ(Signal* signal)
+{
+ OperationrecPtr tatrOpPtr;
+
+ jamEntry();
+ tatrOpPtr.i = signal->theData[1]; /* OPER PTR OF ACC */
+ ptrCheckGuard(tatrOpPtr, coprecsize, operationrec);
+ if (tatrOpPtr.p->operation == ZSCAN_OP) {
+ tatrOpPtr.p->transId1 = signal->theData[2];
+ tatrOpPtr.p->transId2 = signal->theData[3];
+ } else {
+ jam();
+ signal->theData[0] = cminusOne;
+ signal->theData[1] = ZTO_OP_STATE_ERROR;
+ }//if
+ return;
+}//Dbacc::execACC_TO_REQ()
+
+/* --------------------------------------------------------------------------------- */
+/* CONTAINERINFO */
+/* INPUT: */
+/* CI_PAGEIDPTR (PAGE POINTER WHERE CONTAINER RESIDES) */
+/* TCI_PAGEINDEX (INDEX OF CONTAINER, USED TO CALCULATE PAGE INDEX) */
+/* TCI_ISFORWARD (DIRECTION OF CONTAINER FORWARD OR BACKWARD) */
+/* */
+/* OUTPUT: */
+/* TCI_CONTAINERPTR (A POINTER TO THE HEAD OF THE CONTAINER) */
+/* TCI_CONTAINERLEN (LENGTH OF THE CONTAINER */
+/* TCI_CONTAINERHEAD (THE HEADER OF THE CONTAINER) */
+/* */
+/* DESCRIPTION: THE ADDRESS OF THE CONTAINER WILL BE CALCULATED AND */
+/* ALL INFORMATION ABOUT THE CONTAINER WILL BE READ */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::containerinfo(Signal* signal)
+{
+ tciContainerptr = (tciPageindex << ZSHIFT_PLUS) - (tciPageindex << ZSHIFT_MINUS);
+ if (tciIsforward == ZTRUE) {
+ jam();
+ tciContainerptr = tciContainerptr + ZHEAD_SIZE;
+ } else {
+ jam();
+ tciContainerptr = ((tciContainerptr + ZHEAD_SIZE) + ZBUF_SIZE) - ZCON_HEAD_SIZE;
+ }//if
+ arrGuard(tciContainerptr, 2048);
+ tciContainerhead = ciPageidptr.p->word32[tciContainerptr];
+ tciContainerlen = tciContainerhead >> 26;
+}//Dbacc::containerinfo()
+
+/* --------------------------------------------------------------------------------- */
+/* GET_SCAN_ELEMENT */
+/* INPUT: GSE_PAGEIDPTR */
+/* TGSE_PAGEINDEX */
+/* OUTPUT: TGSE_IS_LOCKED (IF TRESULT /= ZFALSE) */
+/* GSE_PAGEIDPTR */
+/* TGSE_PAGEINDEX */
+/* --------------------------------------------------------------------------------- */
+bool Dbacc::getScanElement(Signal* signal)
+{
+ tgseIsforward = ZTRUE;
+ NEXTSEARCH_SCAN_LOOP:
+ ciPageidptr.i = gsePageidptr.i;
+ ciPageidptr.p = gsePageidptr.p;
+ tciPageindex = tgsePageindex;
+ tciIsforward = tgseIsforward;
+ containerinfo(signal);
+ sscPageidptr.i = gsePageidptr.i;
+ sscPageidptr.p = gsePageidptr.p;
+ tsscContainerlen = tciContainerlen;
+ tsscContainerptr = tciContainerptr;
+ tsscIsforward = tciIsforward;
+ if (searchScanContainer(signal)) {
+ jam();
+ tgseIsLocked = tsscIsLocked;
+ tgseElementptr = tsscElementptr;
+ tgseContainerptr = tsscContainerptr;
+ return true;
+ }//if
+ if (((tciContainerhead >> 7) & 0x3) != 0) {
+ jam();
+ nciPageidptr.i = gsePageidptr.i;
+ nciPageidptr.p = gsePageidptr.p;
+ tnciContainerhead = tciContainerhead;
+ tnciContainerptr = tciContainerptr;
+ nextcontainerinfo(signal);
+ tgsePageindex = tnciPageindex;
+ gsePageidptr.i = nciPageidptr.i;
+ gsePageidptr.p = nciPageidptr.p;
+ tgseIsforward = tnciIsforward;
+ goto NEXTSEARCH_SCAN_LOOP;
+ }//if
+ return false;
+}//Dbacc::getScanElement()
+
+/* --------------------------------------------------------------------------------- */
+/* INIT_SCAN_OP_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initScanOpRec(Signal* signal)
+{
+ Uint32 tisoTmp;
+ Uint32 tisoLocalPtr;
+ Uint32 guard24;
+
+ scanPtr.p->scanOpsAllocated++;
+
+ operationRecPtr.p->scanRecPtr = scanPtr.i;
+ operationRecPtr.p->operation = ZSCAN_OP;
+ operationRecPtr.p->transactionstate = ACTIVE;
+ operationRecPtr.p->commitDeleteCheckFlag = ZFALSE;
+ operationRecPtr.p->lockMode = scanPtr.p->scanLockMode;
+ operationRecPtr.p->fid = fragrecptr.p->myfid;
+ operationRecPtr.p->fragptr = fragrecptr.i;
+ operationRecPtr.p->elementIsDisappeared = ZFALSE;
+ operationRecPtr.p->nextParallelQue = RNIL;
+ operationRecPtr.p->prevParallelQue = RNIL;
+ operationRecPtr.p->nextSerialQue = RNIL;
+ operationRecPtr.p->prevSerialQue = RNIL;
+ operationRecPtr.p->prevQueOp = RNIL;
+ operationRecPtr.p->nextQueOp = RNIL;
+ operationRecPtr.p->keyinfoPage = RNIL; // Safety precaution
+ operationRecPtr.p->transId1 = scanPtr.p->scanTrid1;
+ operationRecPtr.p->transId2 = scanPtr.p->scanTrid2;
+ operationRecPtr.p->lockOwner = ZFALSE;
+ operationRecPtr.p->dirtyRead = 0;
+ operationRecPtr.p->nodeType = 0; // Not a stand-by node
+ operationRecPtr.p->elementIsforward = tisoIsforward;
+ operationRecPtr.p->elementContainer = tisoContainerptr;
+ operationRecPtr.p->elementPointer = tisoElementptr;
+ operationRecPtr.p->elementPage = isoPageptr.i;
+ operationRecPtr.p->isAccLockReq = ZFALSE;
+ operationRecPtr.p->isUndoLogReq = ZFALSE;
+ tisoLocalPtr = tisoElementptr + tisoIsforward;
+ guard24 = fragrecptr.p->localkeylen - 1;
+ for (tisoTmp = 0; tisoTmp <= guard24; tisoTmp++) {
+ arrGuard(tisoTmp, 2);
+ arrGuard(tisoLocalPtr, 2048);
+ operationRecPtr.p->localdata[tisoTmp] = isoPageptr.p->word32[tisoLocalPtr];
+ tisoLocalPtr = tisoLocalPtr + tisoIsforward;
+ }//for
+ arrGuard(tisoLocalPtr, 2048);
+ operationRecPtr.p->keydata[0] = isoPageptr.p->word32[tisoLocalPtr];
+ operationRecPtr.p->tupkeylen = fragrecptr.p->keyLength;
+ operationRecPtr.p->xfrmtupkeylen = 0; // not used
+}//Dbacc::initScanOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* NEXTCONTAINERINFO */
+/* DESCRIPTION:THE CONTAINER HEAD WILL BE CHECKED TO CALCULATE INFORMATION */
+/* ABOUT NEXT CONTAINER IN THE BUCKET. */
+/* INPUT: TNCI_CONTAINERHEAD */
+/* NCI_PAGEIDPTR */
+/* TNCI_CONTAINERPTR */
+/* OUTPUT: */
+/* TNCI_PAGEINDEX (INDEX FROM WHICH PAGE INDEX CAN BE CALCULATED). */
+/* TNCI_ISFORWARD (IS THE NEXT CONTAINER FORWARD (+1) OR BACKWARD (-1) */
+/* NCI_PAGEIDPTR (PAGE REFERENCE OF NEXT CONTAINER) */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::nextcontainerinfo(Signal* signal)
+{
+ tnciNextSamePage = (tnciContainerhead >> 9) & 0x1; /* CHECK BIT FOR CHECKING WHERE */
+ /* THE NEXT CONTAINER IS IN THE SAME PAGE */
+ tnciPageindex = tnciContainerhead & 0x7f; /* NEXT CONTAINER PAGE INDEX 7 BITS */
+ if (((tnciContainerhead >> 7) & 3) == ZLEFT) {
+ jam();
+ tnciIsforward = ZTRUE;
+ } else {
+ jam();
+ tnciIsforward = cminusOne;
+ }//if
+ if (tnciNextSamePage == ZFALSE) {
+ jam();
+ /* NEXT CONTAINER IS IN AN OVERFLOW PAGE */
+ arrGuard(tnciContainerptr + 1, 2048);
+ tnciTmp = nciPageidptr.p->word32[tnciContainerptr + 1];
+ nciOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ ptrCheckGuard(nciOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard((tnciTmp >> 8), 256);
+ nciOverflowDirptr.i = nciOverflowrangeptr.p->dirArray[tnciTmp >> 8];
+ ptrCheckGuard(nciOverflowDirptr, cdirarraysize, directoryarray);
+ nciPageidptr.i = nciOverflowDirptr.p->pagep[tnciTmp & 0xff];
+ ptrCheckGuard(nciPageidptr, cpagesize, page8);
+ }//if
+}//Dbacc::nextcontainerinfo()
+
+/* --------------------------------------------------------------------------------- */
+/* PUT_ACTIVE_SCAN_OP */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::putActiveScanOp(Signal* signal)
+{
+ OperationrecPtr pasOperationRecPtr;
+ pasOperationRecPtr.i = scanPtr.p->scanFirstActiveOp;
+ if (pasOperationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(pasOperationRecPtr, coprecsize, operationrec);
+ pasOperationRecPtr.p->prevOp = operationRecPtr.i;
+ }//if
+ operationRecPtr.p->nextOp = pasOperationRecPtr.i;
+ operationRecPtr.p->prevOp = RNIL;
+ scanPtr.p->scanFirstActiveOp = operationRecPtr.i;
+}//Dbacc::putActiveScanOp()
+
+/**
+ * putOpScanLockQueue
+ *
+ * Description: Put an operation in the doubly linked
+ * lock list on a scan record. The list is used to
+ * keep track of which operations belonging
+ * to the scan are put in serial lock list of another
+ * operation
+ *
+ * @note Use takeOutScanLockQueue to remove an operation
+ * from the list
+ *
+ */
+void Dbacc::putOpScanLockQue()
+{
+
+#ifdef VM_TRACE
+ // DEBUG CODE
+ // Check that there are as many operations in the lockqueue as
+ // scanLockHeld indicates
+ OperationrecPtr tmpOp;
+ int numLockedOpsBefore = 0;
+ tmpOp.i = scanPtr.p->scanFirstLockedOp;
+ while(tmpOp.i != RNIL){
+ numLockedOpsBefore++;
+ ptrCheckGuard(tmpOp, coprecsize, operationrec);
+ if (tmpOp.p->nextOp == RNIL)
+ ndbrequire(tmpOp.i == scanPtr.p->scanLastLockedOp);
+ tmpOp.i = tmpOp.p->nextOp;
+ }
+ ndbrequire(numLockedOpsBefore==scanPtr.p->scanLockHeld);
+#endif
+
+ OperationrecPtr pslOperationRecPtr;
+ ScanRec theScanRec;
+ theScanRec = *scanPtr.p;
+
+ pslOperationRecPtr.i = scanPtr.p->scanLastLockedOp;
+ operationRecPtr.p->prevOp = pslOperationRecPtr.i;
+ operationRecPtr.p->nextOp = RNIL;
+ if (pslOperationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(pslOperationRecPtr, coprecsize, operationrec);
+ pslOperationRecPtr.p->nextOp = operationRecPtr.i;
+ } else {
+ jam();
+ scanPtr.p->scanFirstLockedOp = operationRecPtr.i;
+ }//if
+ scanPtr.p->scanLastLockedOp = operationRecPtr.i;
+ scanPtr.p->scanLockHeld++;
+
+}//Dbacc::putOpScanLockQue()
+
+/* --------------------------------------------------------------------------------- */
+/* PUT_READY_SCAN_QUEUE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::putReadyScanQueue(Signal* signal, Uint32 scanRecIndex)
+{
+ OperationrecPtr prsOperationRecPtr;
+ ScanRecPtr TscanPtr;
+
+ TscanPtr.i = scanRecIndex;
+ ptrCheckGuard(TscanPtr, cscanRecSize, scanRec);
+
+ prsOperationRecPtr.i = TscanPtr.p->scanLastQueuedOp;
+ operationRecPtr.p->prevOp = prsOperationRecPtr.i;
+ operationRecPtr.p->nextOp = RNIL;
+ TscanPtr.p->scanLastQueuedOp = operationRecPtr.i;
+ if (prsOperationRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(prsOperationRecPtr, coprecsize, operationrec);
+ prsOperationRecPtr.p->nextOp = operationRecPtr.i;
+ } else {
+ jam();
+ TscanPtr.p->scanFirstQueuedOp = operationRecPtr.i;
+ }//if
+}//Dbacc::putReadyScanQueue()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_SCAN_BUCKET */
+// Input:
+// rsbPageidptr.i Index to page where buckets starts
+// rsbPageidptr.p Pointer to page where bucket starts
+// trsbPageindex Page index of starting container in bucket
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseScanBucket(Signal* signal)
+{
+ Uint32 trsbIsforward;
+
+ trsbIsforward = ZTRUE;
+ NEXTRELEASESCANLOOP:
+ ciPageidptr.i = rsbPageidptr.i;
+ ciPageidptr.p = rsbPageidptr.p;
+ tciPageindex = trsbPageindex;
+ tciIsforward = trsbIsforward;
+ containerinfo(signal);
+ rscPageidptr.i = rsbPageidptr.i;
+ rscPageidptr.p = rsbPageidptr.p;
+ trscContainerlen = tciContainerlen;
+ trscContainerptr = tciContainerptr;
+ trscIsforward = trsbIsforward;
+ releaseScanContainer(signal);
+ if (((tciContainerhead >> 7) & 0x3) != 0) {
+ jam();
+ nciPageidptr.i = rsbPageidptr.i;
+ nciPageidptr.p = rsbPageidptr.p;
+ tnciContainerhead = tciContainerhead;
+ tnciContainerptr = tciContainerptr;
+ nextcontainerinfo(signal);
+ rsbPageidptr.i = nciPageidptr.i;
+ rsbPageidptr.p = nciPageidptr.p;
+ trsbPageindex = tnciPageindex;
+ trsbIsforward = tnciIsforward;
+ goto NEXTRELEASESCANLOOP;
+ }//if
+}//Dbacc::releaseScanBucket()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_SCAN_CONTAINER */
+/* INPUT: TRSC_CONTAINERLEN */
+/* RSC_PAGEIDPTR */
+/* TRSC_CONTAINERPTR */
+/* TRSC_ISFORWARD */
+/* SCAN_PTR */
+/* */
+/* DESCRIPTION: SEARCHS IN A CONTAINER, AND THE SCAN BIT OF THE ELEMENTS */
+/* OF THE CONTAINER IS RESET */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseScanContainer(Signal* signal)
+{
+ OperationrecPtr rscOperPtr;
+ Uint32 trscElemStep;
+ Uint32 trscElementptr;
+ Uint32 trscElemlens;
+ Uint32 trscElemlen;
+
+ if (trscContainerlen < 4) {
+ if (trscContainerlen != ZCON_HEAD_SIZE) {
+ jam();
+ sendSystemerror(signal);
+ }//if
+ return; /* 2 IS THE MINIMUM SIZE OF THE ELEMENT */
+ }//if
+ trscElemlens = trscContainerlen - ZCON_HEAD_SIZE;
+ trscElemlen = fragrecptr.p->elementLength;
+ if (trscIsforward == 1) {
+ jam();
+ trscElementptr = trscContainerptr + ZCON_HEAD_SIZE;
+ trscElemStep = trscElemlen;
+ } else {
+ jam();
+ trscElementptr = trscContainerptr - 1;
+ trscElemStep = 0 - trscElemlen;
+ }//if
+ do {
+ arrGuard(trscElementptr, 2048);
+ const Uint32 eh = rscPageidptr.p->word32[trscElementptr];
+ const Uint32 scanMask = scanPtr.p->scanMask;
+ if (ElementHeader::getUnlocked(eh)) {
+ jam();
+ const Uint32 tmp = ElementHeader::clearScanBit(eh, scanMask);
+ dbgWord32(rscPageidptr, trscElementptr, tmp);
+ rscPageidptr.p->word32[trscElementptr] = tmp;
+ } else {
+ jam();
+ rscOperPtr.i = ElementHeader::getOpPtrI(eh);
+ ptrCheckGuard(rscOperPtr, coprecsize, operationrec);
+ rscOperPtr.p->scanBits &= ~scanMask;
+ }//if
+ trscElemlens = trscElemlens - trscElemlen;
+ trscElementptr = trscElementptr + trscElemStep;
+ } while (trscElemlens > 1);
+ if (trscElemlens != 0) {
+ jam();
+ sendSystemerror(signal);
+ }//if
+}//Dbacc::releaseScanContainer()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_SCAN_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseScanRec(Signal* signal)
+{
+ // Check that all ops this scan has allocated have been
+ // released
+ ndbrequire(scanPtr.p->scanOpsAllocated==0);
+
+ // Check that all locks this scan might have aquired
+ // have been properly released
+ ndbrequire(scanPtr.p->scanLockHeld == 0);
+ ndbrequire(scanPtr.p->scanFirstLockedOp == RNIL);
+ ndbrequire(scanPtr.p->scanLastLockedOp == RNIL);
+
+ // Check that all active operations have been
+ // properly released
+ ndbrequire(scanPtr.p->scanFirstActiveOp == RNIL);
+
+ // Check that all queued operations have been
+ // properly released
+ ndbrequire(scanPtr.p->scanFirstQueuedOp == RNIL);
+ ndbrequire(scanPtr.p->scanLastQueuedOp == RNIL);
+
+ // Put scan record in free list
+ scanPtr.p->scanNextfreerec = cfirstFreeScanRec;
+ scanPtr.p->scanState = ScanRec::SCAN_DISCONNECT;
+ cfirstFreeScanRec = scanPtr.i;
+
+}//Dbacc::releaseScanRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEARCH_SCAN_CONTAINER */
+/* INPUT: TSSC_CONTAINERLEN */
+/* TSSC_CONTAINERPTR */
+/* TSSC_ISFORWARD */
+/* SSC_PAGEIDPTR */
+/* SCAN_PTR */
+/* OUTPUT: TSSC_IS_LOCKED */
+/* */
+/* DESCRIPTION: SEARCH IN A CONTAINER TO FIND THE NEXT SCAN ELEMENT. */
+/* TO DO THIS THE SCAN BIT OF THE ELEMENT HEADER IS CHECKED. IF */
+/* THIS BIT IS ZERO, IT IS SET TO ONE AND THE ELEMENT IS RETURNED.*/
+/* --------------------------------------------------------------------------------- */
+bool Dbacc::searchScanContainer(Signal* signal)
+{
+ OperationrecPtr sscOperPtr;
+ Uint32 tsscScanBits;
+ Uint32 tsscElemlens;
+ Uint32 tsscElemlen;
+ Uint32 tsscElemStep;
+
+ if (tsscContainerlen < 4) {
+ jam();
+ return false; /* 2 IS THE MINIMUM SIZE OF THE ELEMENT */
+ }//if
+ tsscElemlens = tsscContainerlen - ZCON_HEAD_SIZE;
+ tsscElemlen = fragrecptr.p->elementLength;
+ /* LENGTH OF THE ELEMENT */
+ if (tsscIsforward == 1) {
+ jam();
+ tsscElementptr = tsscContainerptr + ZCON_HEAD_SIZE;
+ tsscElemStep = tsscElemlen;
+ } else {
+ jam();
+ tsscElementptr = tsscContainerptr - 1;
+ tsscElemStep = 0 - tsscElemlen;
+ }//if
+ SCANELEMENTLOOP001:
+ arrGuard(tsscElementptr, 2048);
+ const Uint32 eh = sscPageidptr.p->word32[tsscElementptr];
+ tsscIsLocked = ElementHeader::getLocked(eh);
+ if (!tsscIsLocked){
+ jam();
+ tsscScanBits = ElementHeader::getScanBits(eh);
+ if ((scanPtr.p->scanMask & tsscScanBits) == 0) {
+ jam();
+ const Uint32 tmp = ElementHeader::setScanBit(eh, scanPtr.p->scanMask);
+ dbgWord32(sscPageidptr, tsscElementptr, tmp);
+ sscPageidptr.p->word32[tsscElementptr] = tmp;
+ return true;
+ }//if
+ } else {
+ jam();
+ sscOperPtr.i = ElementHeader::getOpPtrI(eh);
+ ptrCheckGuard(sscOperPtr, coprecsize, operationrec);
+ if ((sscOperPtr.p->scanBits & scanPtr.p->scanMask) == 0) {
+ jam();
+ sscOperPtr.p->scanBits |= scanPtr.p->scanMask;
+ return true;
+ }//if
+ }//if
+ /* THE ELEMENT IS ALREADY SENT. */
+ /* SEARCH FOR NEXT ONE */
+ tsscElemlens = tsscElemlens - tsscElemlen;
+ if (tsscElemlens > 1) {
+ jam();
+ tsscElementptr = tsscElementptr + tsscElemStep;
+ goto SCANELEMENTLOOP001;
+ }//if
+ return false;
+}//Dbacc::searchScanContainer()
+
+/* --------------------------------------------------------------------------------- */
+/* SEND THE RESPONSE NEXT_SCANCONF AND POSSIBLE KEYINFO SIGNALS AS WELL. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::sendNextScanConf(Signal* signal)
+{
+ scanPtr.p->scanTimer = scanPtr.p->scanContinuebCounter;
+ Uint32 blockNo = refToBlock(scanPtr.p->scanUserblockref);
+ jam();
+ /** ---------------------------------------------------------------------
+ * LQH WILL NOT HAVE ANY USE OF THE TUPLE KEY LENGTH IN THIS CASE AND
+ * SO WE DO NOT PROVIDE IT. IN THIS CASE THESE VALUES ARE UNDEFINED.
+ * ---------------------------------------------------------------------- */
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = operationRecPtr.i;
+ signal->theData[2] = operationRecPtr.p->fid;
+ signal->theData[3] = operationRecPtr.p->localdata[0];
+ signal->theData[4] = operationRecPtr.p->localdata[1];
+ signal->theData[5] = fragrecptr.p->localkeylen;
+ EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 6);
+ return;
+}//Dbacc::sendNextScanConf()
+
+/*---------------------------------------------------------------------------
+ * sendScanHbRep
+ * Description: Using Dispatcher::execute() to send a heartbeat to DBTC
+ * from DBLQH telling the scan is alive. We use the sendScanHbRep()
+ * in DBLQH, this needs to be done here in DBACC since it can take
+ * a while before LQH receives an answer the normal way from ACC.
+ *--------------------------------------------------------------------------*/
+void Dbacc::sendScanHbRep(Signal* signal, Uint32 scanPtrIndex)
+{
+ scanPtr.i = scanPtrIndex;
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+
+ // If the timer status is on we continue with a new heartbeat in one second,
+ // else the loop stops and we will not send a new CONTINUEB
+ if (scanPtr.p->scanTimer != 0){
+ if (scanPtr.p->scanTimer == scanPtr.p->scanContinuebCounter){
+ jam();
+ ndbrequire(scanPtr.p->scanState != ScanRec::SCAN_DISCONNECT);
+
+ signal->theData[0] = scanPtr.p->scanUserptr;
+ signal->theData[1] = scanPtr.p->scanTrid1;
+ signal->theData[2] = scanPtr.p->scanTrid2;
+ EXECUTE_DIRECT(DBLQH, GSN_SCAN_HBREP, signal, 3);
+ jamEntry();
+ }//if
+ scanPtr.p->scanContinuebCounter++;
+ signal->theData[0] = ZSEND_SCAN_HBREP;
+ signal->theData[1] = scanPtr.i;
+ sendSignalWithDelay(cownBlockref, GSN_CONTINUEB, signal, 100, 2);
+ } else {
+ jam();
+ scanPtr.p->scanContinuebCounter = 0;
+ }//if
+}//Dbacc::sendScanHbRep()
+
+/* --------------------------------------------------------------------------------- */
+/* SETLOCK */
+/* DESCRIPTION:SETS LOCK ON AN ELEMENT. INFORMATION ABOUT THE ELEMENT IS */
+/* SAVED IN THE ELEMENT HEAD.A COPY OF THIS INFORMATION WILL */
+/* BE PUT IN THE OPERATION RECORD. A FIELD IN THE HEADER OF */
+/* THE ELEMENT POINTS TO THE OPERATION RECORD. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::setlock(Signal* signal)
+{
+ Uint32 tselTmp1;
+
+ arrGuard(tslElementptr, 2048);
+ tselTmp1 = slPageidptr.p->word32[tslElementptr];
+ operationRecPtr.p->scanBits = ElementHeader::getScanBits(tselTmp1);
+ operationRecPtr.p->hashvaluePart = ElementHeader::getHashValuePart(tselTmp1);
+
+ tselTmp1 = ElementHeader::setLocked(operationRecPtr.i);
+ dbgWord32(slPageidptr, tslElementptr, tselTmp1);
+ slPageidptr.p->word32[tslElementptr] = tselTmp1;
+}//Dbacc::setlock()
+
+/* --------------------------------------------------------------------------------- */
+/* TAKE_OUT_ACTIVE_SCAN_OP */
+/* DESCRIPTION: AN ACTIVE SCAN OPERATION IS BELOGED TO AN ACTIVE LIST OF THE */
+/* SCAN RECORD. BY THIS SUBRUTIN THE LIST IS UPDATED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::takeOutActiveScanOp(Signal* signal)
+{
+ OperationrecPtr tasOperationRecPtr;
+
+ if (operationRecPtr.p->prevOp != RNIL) {
+ jam();
+ tasOperationRecPtr.i = operationRecPtr.p->prevOp;
+ ptrCheckGuard(tasOperationRecPtr, coprecsize, operationrec);
+ tasOperationRecPtr.p->nextOp = operationRecPtr.p->nextOp;
+ } else {
+ jam();
+ scanPtr.p->scanFirstActiveOp = operationRecPtr.p->nextOp;
+ }//if
+ if (operationRecPtr.p->nextOp != RNIL) {
+ jam();
+ tasOperationRecPtr.i = operationRecPtr.p->nextOp;
+ ptrCheckGuard(tasOperationRecPtr, coprecsize, operationrec);
+ tasOperationRecPtr.p->prevOp = operationRecPtr.p->prevOp;
+ }//if
+}//Dbacc::takeOutActiveScanOp()
+
+/**
+ * takeOutScanLockQueue
+ *
+ * Description: Take out an operation from the doubly linked
+ * lock list on a scan record.
+ *
+ * @note Use putOpScanLockQue to insert a operation in
+ * the list
+ *
+ */
+void Dbacc::takeOutScanLockQueue(Uint32 scanRecIndex)
+{
+ OperationrecPtr tslOperationRecPtr;
+ ScanRecPtr TscanPtr;
+
+ TscanPtr.i = scanRecIndex;
+ ptrCheckGuard(TscanPtr, cscanRecSize, scanRec);
+
+ if (operationRecPtr.p->prevOp != RNIL) {
+ jam();
+ tslOperationRecPtr.i = operationRecPtr.p->prevOp;
+ ptrCheckGuard(tslOperationRecPtr, coprecsize, operationrec);
+ tslOperationRecPtr.p->nextOp = operationRecPtr.p->nextOp;
+ } else {
+ jam();
+ // Check that first are pointing at operation to take out
+ ndbrequire(TscanPtr.p->scanFirstLockedOp==operationRecPtr.i);
+ TscanPtr.p->scanFirstLockedOp = operationRecPtr.p->nextOp;
+ }//if
+ if (operationRecPtr.p->nextOp != RNIL) {
+ jam();
+ tslOperationRecPtr.i = operationRecPtr.p->nextOp;
+ ptrCheckGuard(tslOperationRecPtr, coprecsize, operationrec);
+ tslOperationRecPtr.p->prevOp = operationRecPtr.p->prevOp;
+ } else {
+ jam();
+ // Check that last are pointing at operation to take out
+ ndbrequire(TscanPtr.p->scanLastLockedOp==operationRecPtr.i);
+ TscanPtr.p->scanLastLockedOp = operationRecPtr.p->prevOp;
+ }//if
+ TscanPtr.p->scanLockHeld--;
+
+#ifdef VM_TRACE
+ // DEBUG CODE
+ // Check that there are as many operations in the lockqueue as
+ // scanLockHeld indicates
+ OperationrecPtr tmpOp;
+ int numLockedOps = 0;
+ tmpOp.i = TscanPtr.p->scanFirstLockedOp;
+ while(tmpOp.i != RNIL){
+ numLockedOps++;
+ ptrCheckGuard(tmpOp, coprecsize, operationrec);
+ if (tmpOp.p->nextOp == RNIL)
+ ndbrequire(tmpOp.i == TscanPtr.p->scanLastLockedOp);
+ tmpOp.i = tmpOp.p->nextOp;
+ }
+ ndbrequire(numLockedOps==TscanPtr.p->scanLockHeld);
+#endif
+}//Dbacc::takeOutScanLockQueue()
+
+/* --------------------------------------------------------------------------------- */
+/* TAKE_OUT_READY_SCAN_QUEUE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::takeOutReadyScanQueue(Signal* signal)
+{
+ OperationrecPtr trsOperationRecPtr;
+
+ if (operationRecPtr.p->prevOp != RNIL) {
+ jam();
+ trsOperationRecPtr.i = operationRecPtr.p->prevOp;
+ ptrCheckGuard(trsOperationRecPtr, coprecsize, operationrec);
+ trsOperationRecPtr.p->nextOp = operationRecPtr.p->nextOp;
+ } else {
+ jam();
+ scanPtr.p->scanFirstQueuedOp = operationRecPtr.p->nextOp;
+ }//if
+ if (operationRecPtr.p->nextOp != RNIL) {
+ jam();
+ trsOperationRecPtr.i = operationRecPtr.p->nextOp;
+ ptrCheckGuard(trsOperationRecPtr, coprecsize, operationrec);
+ trsOperationRecPtr.p->prevOp = operationRecPtr.p->prevOp;
+ } else {
+ jam();
+ scanPtr.p->scanLastQueuedOp = operationRecPtr.p->nextOp;
+ }//if
+}//Dbacc::takeOutReadyScanQueue()
+
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+/* */
+/* END OF SCAN MODULE */
+/* */
+/* --------------------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------------- */
+
+bool Dbacc::getrootfragmentrec(Signal* signal, RootfragmentrecPtr& rootPtr, Uint32 fid)
+{
+ for (Uint32 i = 0; i < MAX_FRAG_PER_NODE; i++) {
+ jam();
+ if (tabptr.p->fragholder[i] == fid) {
+ jam();
+ rootPtr.i = tabptr.p->fragptrholder[i];
+ ptrCheckGuard(rootPtr, crootfragmentsize, rootfragmentrec);
+ return true;
+ }//if
+ }//for
+ return false;
+}//Dbacc::getrootfragmentrec()
+
+/* --------------------------------------------------------------------------------- */
+/* INIT_FS_OP_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initFsOpRec(Signal* signal)
+{
+ fsOpptr.p->fsOpfragrecPtr = fragrecptr.i;
+ fsOpptr.p->fsConptr = fsConnectptr.i;
+}//Dbacc::initFsOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INIT_LCP_CONN_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initLcpConnRec(Signal* signal)
+{
+ lcpConnectptr.p->lcpUserblockref = tuserblockref;
+ lcpConnectptr.p->lcpUserptr = tuserptr;
+ lcpConnectptr.p->noOfLcpConf = 0; /* NO OF RETUREND CONF SIGNALS */
+ lcpConnectptr.p->syncUndopageState = WAIT_NOTHING;
+}//Dbacc::initLcpConnRec()
+
+/* --------------------------------------------------------------------------------- */
+/* INIT_OVERPAGE */
+/* INPUT. IOP_PAGEPTR, POINTER TO AN OVERFLOW PAGE RECORD */
+/* DESCRIPTION: CONTAINERS AND FREE LISTS OF THE PAGE, GET INITIALE VALUE */
+/* ACCORDING TO LH3 AND PAGE STRUCTOR DESCRIPTION OF NDBACC BLOCK */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initOverpage(Signal* signal)
+{
+ Uint32 tiopTmp;
+ Uint32 tiopPrevFree;
+ Uint32 tiopNextFree;
+
+ for (tiopIndex = 0; tiopIndex <= 2047; tiopIndex++) {
+ iopPageptr.p->word32[tiopIndex] = 0;
+ }//for
+ iopPageptr.p->word32[ZPOS_OVERFLOWREC] = iopOverflowRecPtr.i;
+ iopPageptr.p->word32[ZPOS_CHECKSUM] = 0;
+ iopPageptr.p->word32[ZPOS_PAGE_ID] = tiopPageId;
+ iopPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] = 0;
+ tiopTmp = ZEMPTYLIST;
+ tiopTmp = (tiopTmp << 16) + (tiopTmp << 23);
+ iopPageptr.p->word32[ZPOS_EMPTY_LIST] = tiopTmp + (1 << ZPOS_PAGE_TYPE_BIT);
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE PREVIOUS PART OF DOUBLY LINKED LIST FOR LEFT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tiopIndex = ZHEAD_SIZE + 1;
+ iopPageptr.p->word32[tiopIndex] = ZEMPTYLIST;
+ for (tiopPrevFree = 0; tiopPrevFree <= ZEMPTYLIST - 2; tiopPrevFree++) {
+ tiopIndex = tiopIndex + ZBUF_SIZE;
+ iopPageptr.p->word32[tiopIndex] = tiopPrevFree;
+ }//for
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE NEXT PART OF DOUBLY LINKED LIST FOR LEFT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tiopIndex = ZHEAD_SIZE;
+ for (tiopNextFree = 1; tiopNextFree <= ZEMPTYLIST - 1; tiopNextFree++) {
+ iopPageptr.p->word32[tiopIndex] = tiopNextFree;
+ tiopIndex = tiopIndex + ZBUF_SIZE;
+ }//for
+ iopPageptr.p->word32[tiopIndex] = ZEMPTYLIST; /* LEFT_LIST IS UPDATED */
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE PREVIOUS PART OF DOUBLY LINKED LIST FOR RIGHT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tiopIndex = (ZBUF_SIZE + ZHEAD_SIZE) - 1;
+ iopPageptr.p->word32[tiopIndex] = ZEMPTYLIST;
+ for (tiopPrevFree = 0; tiopPrevFree <= ZEMPTYLIST - 2; tiopPrevFree++) {
+ tiopIndex = tiopIndex + ZBUF_SIZE;
+ iopPageptr.p->word32[tiopIndex] = tiopPrevFree;
+ }//for
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE NEXT PART OF DOUBLY LINKED LIST FOR RIGHT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tiopIndex = (ZBUF_SIZE + ZHEAD_SIZE) - 2;
+ for (tiopNextFree = 1; tiopNextFree <= ZEMPTYLIST - 1; tiopNextFree++) {
+ iopPageptr.p->word32[tiopIndex] = tiopNextFree;
+ tiopIndex = tiopIndex + ZBUF_SIZE;
+ }//for
+ iopPageptr.p->word32[tiopIndex] = ZEMPTYLIST; /* RIGHT_LIST IS UPDATED */
+}//Dbacc::initOverpage()
+
+/* --------------------------------------------------------------------------------- */
+/* INIT_PAGE */
+/* INPUT. INP_PAGEPTR, POINTER TO A PAGE RECORD */
+/* DESCRIPTION: CONTAINERS AND FREE LISTS OF THE PAGE, GET INITIALE VALUE */
+/* ACCORDING TO LH3 AND PAGE STRUCTOR DISACRIPTION OF NDBACC BLOCK */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::initPage(Signal* signal)
+{
+ Uint32 tinpTmp1;
+ Uint32 tinpIndex;
+ Uint32 tinpTmp;
+ Uint32 tinpPrevFree;
+ Uint32 tinpNextFree;
+
+ for (tiopIndex = 0; tiopIndex <= 2047; tiopIndex++) {
+ inpPageptr.p->word32[tiopIndex] = 0;
+ }//for
+ /* --------------------------------------------------------------------------------- */
+ /* SET PAGE ID FOR USE OF CHECKPOINTER. */
+ /* PREPARE CONTAINER HEADERS INDICATING EMPTY CONTAINERS WITHOUT NEXT. */
+ /* --------------------------------------------------------------------------------- */
+ inpPageptr.p->word32[ZPOS_PAGE_ID] = tipPageId;
+ tinpTmp1 = ZCON_HEAD_SIZE;
+ tinpTmp1 = tinpTmp1 << 26;
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE ZNO_CONTAINERS PREDEFINED HEADERS ON LEFT SIZE. */
+ /* --------------------------------------------------------------------------------- */
+ tinpIndex = ZHEAD_SIZE;
+ for (tinpTmp = 0; tinpTmp <= ZNO_CONTAINERS - 1; tinpTmp++) {
+ inpPageptr.p->word32[tinpIndex] = tinpTmp1;
+ tinpIndex = tinpIndex + ZBUF_SIZE;
+ }//for
+ /* WORD32(ZPOS_EMPTY_LIST) DATA STRUCTURE:*/
+ /*--------------------------------------- */
+ /*| PAGE TYPE|LEFT FREE|RIGHT FREE */
+ /*| 1 | LIST | LIST */
+ /*| BIT | 7 BITS | 7 BITS */
+ /*--------------------------------------- */
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE FIRST POINTER TO DOUBLY LINKED LIST OF FREE CONTAINERS. */
+ /* INITIALISE EMPTY LISTS OF USED CONTAINERS. */
+ /* INITIALISE LEFT FREE LIST TO 64 AND RIGHT FREE LIST TO ZERO. */
+ /* ALSO INITIALISE PAGE TYPE TO NOT OVERFLOW PAGE. */
+ /* --------------------------------------------------------------------------------- */
+ tinpTmp = ZEMPTYLIST;
+ tinpTmp = (tinpTmp << 16) + (tinpTmp << 23);
+ tinpTmp = tinpTmp + (ZNO_CONTAINERS << 7);
+ inpPageptr.p->word32[ZPOS_EMPTY_LIST] = tinpTmp;
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE PREVIOUS PART OF DOUBLY LINKED LIST FOR RIGHT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tinpIndex = (ZHEAD_SIZE + ZBUF_SIZE) - 1;
+ inpPageptr.p->word32[tinpIndex] = ZEMPTYLIST;
+ for (tinpPrevFree = 0; tinpPrevFree <= ZEMPTYLIST - 2; tinpPrevFree++) {
+ tinpIndex = tinpIndex + ZBUF_SIZE;
+ inpPageptr.p->word32[tinpIndex] = tinpPrevFree;
+ }//for
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE NEXT PART OF DOUBLY LINKED LIST FOR RIGHT CONTAINERS. */
+ /* --------------------------------------------------------------------------------- */
+ tinpIndex = (ZHEAD_SIZE + ZBUF_SIZE) - 2;
+ for (tinpNextFree = 1; tinpNextFree <= ZEMPTYLIST - 1; tinpNextFree++) {
+ inpPageptr.p->word32[tinpIndex] = tinpNextFree;
+ tinpIndex = tinpIndex + ZBUF_SIZE;
+ }//for
+ inpPageptr.p->word32[tinpIndex] = ZEMPTYLIST;
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE PREVIOUS PART OF DOUBLY LINKED LIST FOR LEFT CONTAINERS. */
+ /* THE FIRST ZNO_CONTAINERS ARE NOT PUT INTO FREE LIST SINCE THEY ARE */
+ /* PREDEFINED AS OCCUPIED. */
+ /* --------------------------------------------------------------------------------- */
+ tinpIndex = (ZNO_CONTAINERS * ZBUF_SIZE) + ZHEAD_SIZE;
+ for (tinpNextFree = ZNO_CONTAINERS + 1; tinpNextFree <= ZEMPTYLIST - 1; tinpNextFree++) {
+ inpPageptr.p->word32[tinpIndex] = tinpNextFree;
+ tinpIndex = tinpIndex + ZBUF_SIZE;
+ }//for
+ inpPageptr.p->word32[tinpIndex] = ZEMPTYLIST;
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE NEXT PART OF DOUBLY LINKED LIST FOR LEFT CONTAINERS. */
+ /* THE FIRST ZNO_CONTAINERS ARE NOT PUT INTO FREE LIST SINCE THEY ARE */
+ /* PREDEFINED AS OCCUPIED. */
+ /* --------------------------------------------------------------------------------- */
+ tinpIndex = ((ZNO_CONTAINERS * ZBUF_SIZE) + ZHEAD_SIZE) + 1;
+ inpPageptr.p->word32[tinpIndex] = ZEMPTYLIST;
+ for (tinpPrevFree = ZNO_CONTAINERS; tinpPrevFree <= ZEMPTYLIST - 2; tinpPrevFree++) {
+ tinpIndex = tinpIndex + ZBUF_SIZE;
+ inpPageptr.p->word32[tinpIndex] = tinpPrevFree;
+ }//for
+ /* --------------------------------------------------------------------------------- */
+ /* INITIALISE HEADER POSITIONS NOT CURRENTLY USED AND ENSURE USE OF OVERFLOW */
+ /* RECORD POINTER ON THIS PAGE LEADS TO ERROR. */
+ /* --------------------------------------------------------------------------------- */
+ inpPageptr.p->word32[ZPOS_CHECKSUM] = 0;
+ inpPageptr.p->word32[ZPOS_ALLOC_CONTAINERS] = 0;
+ inpPageptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+}//Dbacc::initPage()
+
+/* --------------------------------------------------------------------------------- */
+/* PUT_OP_IN_FRAG_WAIT_QUE */
+/* DESCRIPTION: AN OPERATION WHICH OWNS A LOCK OF AN ELEMENT, IS PUT IN A */
+/* LIST OF THE FRAGMENT. THIS LIST IS USED TO STOP THE QUEUE */
+/* OPERATION DURING CREATE CHECK POINT PROSESS FOR STOP AND */
+/* RESTART OF THE OPERATIONS. */
+/* */
+/* IF CONTINUEB SIGNALS ARE INTRODUCED AFTER STARTING TO EXECUTE ACCKEYREQ WE */
+/* MUST PUT IT IN THIS LIST BEFORE EXITING TO ENSURE THAT WE ARE NOT BEING */
+/* LOCKED AFTER THAT LQH HAS RECEIVED ALL LCP_HOLDOP'S. THEN THE LCP WILL NEVER*/
+/* PROCEED. WE ALSO PUT IT INTO THIS LIST WHEN WAITING FOR LONG KEYS. THIS IS */
+/* ONLY NEEDED IF SIGNALS CAN ENTER BETWEEN THE KEYDATA CARRYING SIGNALS. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::putOpInFragWaitQue(Signal* signal)
+{
+ OperationrecPtr tpiwOperRecPtr;
+
+ if (operationRecPtr.p->operation != ZSCAN_OP) {
+ if (fragrecptr.p->firstWaitInQueOp == RNIL) {
+ jam();
+ fragrecptr.p->firstWaitInQueOp = operationRecPtr.i;
+ } else {
+ jam();
+ tpiwOperRecPtr.i = fragrecptr.p->lastWaitInQueOp;
+ ptrCheckGuard(tpiwOperRecPtr, coprecsize, operationrec);
+ tpiwOperRecPtr.p->nextQueOp = operationRecPtr.i;
+ }//if
+ operationRecPtr.p->opState = WAIT_IN_QUEUE;
+ operationRecPtr.p->nextQueOp = RNIL;
+ operationRecPtr.p->prevQueOp = fragrecptr.p->lastWaitInQueOp;
+ fragrecptr.p->lastWaitInQueOp = operationRecPtr.i;
+ }//if
+}//Dbacc::putOpInFragWaitQue()
+
+/* --------------------------------------------------------------------------------- */
+/* PUT_OVERFLOW_REC_IN_FRAG */
+/* DESCRIPTION: AN OVERFLOW RECORD WITCH IS USED TO KEEP INFORMATION ABOUT */
+/* OVERFLOW PAGE WILL BE PUT IN A LIST OF OVERFLOW RECORDS IN */
+/* THE FRAGMENT RECORD. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::putOverflowRecInFrag(Signal* signal)
+{
+ OverflowRecordPtr tpifNextOverrecPtr;
+ OverflowRecordPtr tpifPrevOverrecPtr;
+
+ tpifNextOverrecPtr.i = fragrecptr.p->firstOverflowRec;
+ tpifPrevOverrecPtr.i = RNIL;
+ while (tpifNextOverrecPtr.i != RNIL) {
+ ptrCheckGuard(tpifNextOverrecPtr, coverflowrecsize, overflowRecord);
+ if (tpifNextOverrecPtr.p->dirindex < porOverflowRecPtr.p->dirindex) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* PROCEED IN LIST TO THE NEXT IN THE LIST SINCE THE ENTRY HAD A LOWER PAGE ID.*/
+ /* WE WANT TO ENSURE THAT LOWER PAGE ID'S ARE KEPT FULL RATHER THAN THE */
+ /* OPPOSITE TO ENSURE THAT HIGH PAGE ID'S CAN BE REMOVED WHEN SHRINKS ARE */
+ /* PERFORMED. */
+ /* --------------------------------------------------------------------------------- */
+ tpifPrevOverrecPtr = tpifNextOverrecPtr;
+ tpifNextOverrecPtr.i = tpifNextOverrecPtr.p->nextOverRec;
+ } else {
+ jam();
+ ndbrequire(tpifNextOverrecPtr.p->dirindex != porOverflowRecPtr.p->dirindex);
+ /* --------------------------------------------------------------------------------- */
+ /* TRYING TO INSERT THE SAME PAGE TWICE. SYSTEM ERROR. */
+ /* --------------------------------------------------------------------------------- */
+ break;
+ }//if
+ }//while
+ if (tpifNextOverrecPtr.i == RNIL) {
+ jam();
+ fragrecptr.p->lastOverflowRec = porOverflowRecPtr.i;
+ } else {
+ jam();
+ tpifNextOverrecPtr.p->prevOverRec = porOverflowRecPtr.i;
+ }//if
+ if (tpifPrevOverrecPtr.i == RNIL) {
+ jam();
+ fragrecptr.p->firstOverflowRec = porOverflowRecPtr.i;
+ } else {
+ jam();
+ tpifPrevOverrecPtr.p->nextOverRec = porOverflowRecPtr.i;
+ }//if
+ porOverflowRecPtr.p->prevOverRec = tpifPrevOverrecPtr.i;
+ porOverflowRecPtr.p->nextOverRec = tpifNextOverrecPtr.i;
+}//Dbacc::putOverflowRecInFrag()
+
+/* --------------------------------------------------------------------------------- */
+/* PUT_REC_IN_FREE_OVERDIR */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::putRecInFreeOverdir(Signal* signal)
+{
+ OverflowRecordPtr tpfoNextOverrecPtr;
+ OverflowRecordPtr tpfoPrevOverrecPtr;
+
+ tpfoNextOverrecPtr.i = fragrecptr.p->firstFreeDirindexRec;
+ tpfoPrevOverrecPtr.i = RNIL;
+ while (tpfoNextOverrecPtr.i != RNIL) {
+ ptrCheckGuard(tpfoNextOverrecPtr, coverflowrecsize, overflowRecord);
+ if (tpfoNextOverrecPtr.p->dirindex < priOverflowRecPtr.p->dirindex) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* PROCEED IN LIST TO THE NEXT IN THE LIST SINCE THE ENTRY HAD A LOWER PAGE ID.*/
+ /* WE WANT TO ENSURE THAT LOWER PAGE ID'S ARE KEPT FULL RATHER THAN THE */
+ /* OPPOSITE TO ENSURE THAT HIGH PAGE ID'S CAN BE REMOVED WHEN SHRINKS ARE */
+ /* PERFORMED. */
+ /* --------------------------------------------------------------------------------- */
+ tpfoPrevOverrecPtr = tpfoNextOverrecPtr;
+ tpfoNextOverrecPtr.i = tpfoNextOverrecPtr.p->nextOverList;
+ } else {
+ jam();
+ ndbrequire(tpfoNextOverrecPtr.p->dirindex != priOverflowRecPtr.p->dirindex);
+ /* --------------------------------------------------------------------------------- */
+ /* ENSURE WE ARE NOT TRYING TO INSERT THE SAME PAGE TWICE. */
+ /* --------------------------------------------------------------------------------- */
+ break;
+ }//if
+ }//while
+ if (tpfoNextOverrecPtr.i != RNIL) {
+ jam();
+ tpfoNextOverrecPtr.p->prevOverList = priOverflowRecPtr.i;
+ }//if
+ if (tpfoPrevOverrecPtr.i == RNIL) {
+ jam();
+ fragrecptr.p->firstFreeDirindexRec = priOverflowRecPtr.i;
+ } else {
+ jam();
+ tpfoPrevOverrecPtr.p->nextOverList = priOverflowRecPtr.i;
+ }//if
+ priOverflowRecPtr.p->prevOverList = tpfoPrevOverrecPtr.i;
+ priOverflowRecPtr.p->nextOverList = tpfoNextOverrecPtr.i;
+}//Dbacc::putRecInFreeOverdir()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_DIRECTORY */
+/* --------------------------------------- ----------------------------------------- */
+void Dbacc::releaseDirectory(Signal* signal)
+{
+ ptrCheckGuard(rdDirptr, cdirarraysize, directoryarray);
+ rdDirptr.p->pagep[0] = cfirstfreedir;
+ cfirstfreedir = rdDirptr.i;
+}//Dbacc::releaseDirectory()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_DIRRANGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseDirrange(Signal* signal)
+{
+ ptrCheckGuard(rdDirRangePtr, cdirrangesize, dirRange);
+ rdDirRangePtr.p->dirArray[0] = cfirstfreeDirrange;
+ cfirstfreeDirrange = rdDirRangePtr.i;
+}//Dbacc::releaseDirrange()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_FS_CONN_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseFsConnRec(Signal* signal)
+{
+ fsConnectptr.p->fsNext = cfsFirstfreeconnect;
+ cfsFirstfreeconnect = fsConnectptr.i;
+ fsConnectptr.p->fsState = WAIT_NOTHING;
+}//Dbacc::releaseFsConnRec()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_FS_OP_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseFsOpRec(Signal* signal)
+{
+ fsOpptr.p->fsOpnext = cfsFirstfreeop;
+ cfsFirstfreeop = fsOpptr.i;
+ fsOpptr.p->fsOpstate = WAIT_NOTHING;
+}//Dbacc::releaseFsOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_LCP_CONNECT_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseLcpConnectRec(Signal* signal)
+{
+ lcpConnectptr.p->lcpstate = LCP_FREE;
+ lcpConnectptr.p->nextLcpConn = cfirstfreelcpConnect;
+ lcpConnectptr.p->lcpstate = LCP_FREE;
+ cfirstfreelcpConnect = lcpConnectptr.i;
+}//Dbacc::releaseLcpConnectRec()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE OP RECORD */
+/* PUT A FREE OPERATION IN A FREE LIST OF THE OPERATIONS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseOpRec(Signal* signal)
+{
+#if 0
+ // DEBUG CODE
+ // Check that the operation to be released isn't
+ // already in the list of free operations
+ // Since this code loops through the entire list of free operations
+ // it's only enabled in VM_TRACE mode
+ OperationrecPtr opRecPtr;
+ bool opInList = false;
+ opRecPtr.i = cfreeopRec;
+ while (opRecPtr.i != RNIL){
+ if (opRecPtr.i == operationRecPtr.i){
+ opInList = true;
+ break;
+ }
+ ptrCheckGuard(opRecPtr, coprecsize, operationrec);
+ opRecPtr.i = opRecPtr.p->nextOp;
+ }
+ ndbrequire(opInList == false);
+#endif
+ ndbrequire(operationRecPtr.p->lockOwner == ZFALSE);
+
+ operationRecPtr.p->nextOp = cfreeopRec;
+ cfreeopRec = operationRecPtr.i; /* UPDATE FREE LIST OF OP RECORDS */
+ operationRecPtr.p->prevOp = RNIL;
+ operationRecPtr.p->opState = FREE_OP;
+ operationRecPtr.p->transactionstate = IDLE;
+ operationRecPtr.p->operation = ZUNDEFINED_OP;
+}//Dbacc::releaseOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_OVERFLOW_REC */
+/* PUT A FREE OVERFLOW REC IN A FREE LIST OF THE OVERFLOW RECORDS */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseOverflowRec(Signal* signal)
+{
+ rorOverflowRecPtr.p->nextfreeoverrec = cfirstfreeoverrec;
+ cfirstfreeoverrec = rorOverflowRecPtr.i;
+}//Dbacc::releaseOverflowRec()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_OVERPAGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseOverpage(Signal* signal)
+{
+ DirRangePtr ropOverflowrangeptr;
+ DirectoryarrayPtr ropOverflowDirptr;
+ OverflowRecordPtr ropOverflowRecPtr;
+ OverflowRecordPtr tuodOverflowRecPtr;
+ Uint32 tropTmp;
+ Uint32 tropTmp1;
+ Uint32 tropTmp2;
+
+ ropOverflowRecPtr.i = ropPageptr.p->word32[ZPOS_OVERFLOWREC];
+ ndbrequire(ropOverflowRecPtr.i != RNIL);
+ /* THE OVERFLOW REC WILL BE TAKEN OUT OF THE */
+ /* FREELIST OF OVERFLOW PAGE WITH FREE */
+ /* CONTAINER AND WILL BE PUT IN THE FREE LIST */
+ /* OF THE FREE DIRECTORY INDEXES. */
+ if ((fragrecptr.p->lastOverflowRec == ropOverflowRecPtr.i) &&
+ (fragrecptr.p->firstOverflowRec == ropOverflowRecPtr.i)) {
+ jam();
+ return; /* THERE IS ONLY ONE OVERFLOW PAGE */
+ }//if
+ if ((fragrecptr.p->createLcp == ZTRUE) &&
+ (fragrecptr.p->lcpMaxOverDirIndex > ropPageptr.p->word32[ZPOS_PAGE_ID])) {
+ /* --------------------------------------------------------------------------------- */
+ /* THE PAGE PARTICIPATES IN THE LOCAL CHECKPOINT. */
+ /* --------------------------------------------------------------------------------- */
+ if (fragrecptr.p->fragState == LCP_SEND_PAGES) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* THE PAGE PARTICIPATES IN THE LOCAL CHECKPOINT AND THE WRITE TO DISK HAS NOT */
+ /* YET BEEN COMPLETED. WE MUST KEEP IT A WHILE LONGER SINCE AN EMPTY PAGE IS */
+ /* NOT EQUIVALENT TO AN INITIALISED PAGE SINCE THE FREE LISTS CAN DIFFER. */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ } else {
+ if ((fragrecptr.p->fragState == LCP_SEND_OVER_PAGES) &&
+ (fragrecptr.p->lcpDirIndex <= ropPageptr.p->word32[ZPOS_PAGE_ID])) {
+ jam();
+ /* --------------------------------------------------------------------------------- */
+ /* SEE COMMENT ABOVE */
+ /* --------------------------------------------------------------------------------- */
+ return;
+ }//if
+ }//if
+ }//if
+#if kalle
+ logicalPage = 0;
+
+ i = fragrecptr.p->directory;
+ p = dirRange.getPtr(i);
+
+ i1 = logicalPage >> 8;
+ i2 = logicalPage & 0xFF;
+
+ ndbrequire(i1 < 256);
+
+ i = p->dirArray[i1];
+ p = directoryarray.getPtr(i);
+
+ physicPageId = p->pagep[i2];
+ physicPageP = page8.getPtr(physicPageId);
+
+ p->pagep[i2] = RNIL;
+ rpPageptr = { physicPageId, physicPageP };
+ releasePage(signal);
+
+#endif
+
+ /* --------------------------------------------------------------------------------- */
+ /* IT WAS OK TO RELEASE THE PAGE. */
+ /* --------------------------------------------------------------------------------- */
+ ptrCheckGuard(ropOverflowRecPtr, coverflowrecsize, overflowRecord);
+ tfoOverflowRecPtr = ropOverflowRecPtr;
+ takeRecOutOfFreeOverpage(signal);
+ ropOverflowRecPtr.p->overpage = RNIL;
+ priOverflowRecPtr = ropOverflowRecPtr;
+ putRecInFreeOverdir(signal);
+ tropTmp = ropPageptr.p->word32[ZPOS_PAGE_ID];
+ ropOverflowrangeptr.i = fragrecptr.p->overflowdir;
+ tropTmp1 = tropTmp >> 8;
+ tropTmp2 = tropTmp & 0xff;
+ ptrCheckGuard(ropOverflowrangeptr, cdirrangesize, dirRange);
+ arrGuard(tropTmp1, 256);
+ ropOverflowDirptr.i = ropOverflowrangeptr.p->dirArray[tropTmp1];
+ ptrCheckGuard(ropOverflowDirptr, cdirarraysize, directoryarray);
+ ropOverflowDirptr.p->pagep[tropTmp2] = RNIL;
+ rpPageptr = ropPageptr;
+ releasePage(signal);
+ if (ropOverflowRecPtr.p->dirindex != (fragrecptr.p->lastOverIndex - 1)) {
+ jam();
+ return;
+ }//if
+ /* --------------------------------------------------------------------------------- */
+ /* THE LAST PAGE IN THE DIRECTORY WAS RELEASED IT IS NOW NECESSARY TO REMOVE */
+ /* ALL RELEASED OVERFLOW DIRECTORIES AT THE END OF THE LIST. */
+ /* --------------------------------------------------------------------------------- */
+ do {
+ fragrecptr.p->lastOverIndex--;
+ if (tropTmp2 == 0) {
+ jam();
+ ndbrequire(tropTmp1 != 0);
+ ropOverflowrangeptr.p->dirArray[tropTmp1] = RNIL;
+ rdDirptr.i = ropOverflowDirptr.i;
+ releaseDirectory(signal);
+ tropTmp1--;
+ tropTmp2 = 255;
+ } else {
+ jam();
+ tropTmp2--;
+ }//if
+ ropOverflowDirptr.i = ropOverflowrangeptr.p->dirArray[tropTmp1];
+ ptrCheckGuard(ropOverflowDirptr, cdirarraysize, directoryarray);
+ } while (ropOverflowDirptr.p->pagep[tropTmp2] == RNIL);
+ /* --------------------------------------------------------------------------------- */
+ /* RELEASE ANY OVERFLOW RECORDS THAT ARE PART OF THE FREE INDEX LIST WHICH */
+ /* DIRECTORY INDEX NOW HAS BEEN RELEASED. */
+ /* --------------------------------------------------------------------------------- */
+ tuodOverflowRecPtr.i = fragrecptr.p->firstFreeDirindexRec;
+ jam();
+ while (tuodOverflowRecPtr.i != RNIL) {
+ jam();
+ ptrCheckGuard(tuodOverflowRecPtr, coverflowrecsize, overflowRecord);
+ if (tuodOverflowRecPtr.p->dirindex >= fragrecptr.p->lastOverIndex) {
+ jam();
+ rorOverflowRecPtr = tuodOverflowRecPtr;
+ troOverflowRecPtr.p = tuodOverflowRecPtr.p;
+ tuodOverflowRecPtr.i = troOverflowRecPtr.p->nextOverList;
+ takeRecOutOfFreeOverdir(signal);
+ releaseOverflowRec(signal);
+ } else {
+ jam();
+ tuodOverflowRecPtr.i = tuodOverflowRecPtr.p->nextOverList;
+ }//if
+ }//while
+}//Dbacc::releaseOverpage()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_PAGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releasePage(Signal* signal)
+{
+#ifdef VM_TRACE
+ bool inList = false;
+ Uint32 numInList = 0;
+ Page8Ptr tmpPagePtr;
+ tmpPagePtr.i = cfirstfreepage;
+ while (tmpPagePtr.i != RNIL){
+ ptrCheckGuard(tmpPagePtr, cpagesize, page8);
+ if (tmpPagePtr.i == rpPageptr.i){
+ jam(); inList = true;
+ break;
+ }
+ numInList++;
+ tmpPagePtr.i = tmpPagePtr.p->word32[0];
+ }
+ ndbrequire(inList == false);
+ // ndbrequire(numInList == cnoOfAllocatedPages);
+#endif
+ rpPageptr.p->word32[0] = cfirstfreepage;
+ cfirstfreepage = rpPageptr.i;
+ cnoOfAllocatedPages--;
+}//Dbacc::releasePage()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_LCP_PAGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseLcpPage(Signal* signal)
+{
+ rlpPageptr.p->word32[0] = cfirstfreeLcpPage;
+ cfirstfreeLcpPage = rlpPageptr.i;
+}//Dbacc::releaseLcpPage()
+
+/* --------------------------------------------------------------------------------- */
+/* RELEASE_SR_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::releaseSrRec(Signal* signal)
+{
+ srVersionPtr.p->nextFreeSr = cfirstFreeSrVersionRec;
+ cfirstFreeSrVersionRec = srVersionPtr.i;
+}//Dbacc::releaseSrRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_DIRECTORY */
+/* DESCRIPTION: A DIRECTORY BLOCK (ZDIRBLOCKSIZE NUMBERS OF DIRECTORY */
+/* RECORDS WILL BE ALLOCATED AND RETURNED. */
+/* SIZE OF DIRECTORY ERROR_CODE, WILL BE RETURNED IF THERE IS NO ANY */
+/* FREE BLOCK */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeDirectory(Signal* signal)
+{
+ Uint32 tsdyIndex;
+
+ if (cfirstfreedir == RNIL) {
+ jam();
+ if (cdirarraysize <= cdirmemory) {
+ jam();
+ tresult = ZDIRSIZE_ERROR;
+ return;
+ } else {
+ jam();
+ sdDirptr.i = cdirmemory;
+ ptrCheckGuard(sdDirptr, cdirarraysize, directoryarray);
+ cdirmemory = cdirmemory + 1;
+ }//if
+ } else {
+ jam();
+ sdDirptr.i = cfirstfreedir;
+ ptrCheckGuard(sdDirptr, cdirarraysize, directoryarray);
+ cfirstfreedir = sdDirptr.p->pagep[0];
+ sdDirptr.p->pagep[0] = RNIL;
+ }//if
+ for (tsdyIndex = 0; tsdyIndex <= 255; tsdyIndex++) {
+ sdDirptr.p->pagep[tsdyIndex] = RNIL;
+ }//for
+}//Dbacc::seizeDirectory()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_DIRRANGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeDirrange(Signal* signal)
+{
+ Uint32 tsdeIndex;
+
+ newDirRangePtr.i = cfirstfreeDirrange;
+ ptrCheckGuard(newDirRangePtr, cdirrangesize, dirRange);
+ cfirstfreeDirrange = newDirRangePtr.p->dirArray[0];
+ for (tsdeIndex = 0; tsdeIndex <= 255; tsdeIndex++) {
+ newDirRangePtr.p->dirArray[tsdeIndex] = RNIL;
+ }//for
+}//Dbacc::seizeDirrange()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE FRAGREC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeFragrec(Signal* signal)
+{
+ fragrecptr.i = cfirstfreefrag;
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ cfirstfreefrag = fragrecptr.p->nextfreefrag;
+ fragrecptr.p->nextfreefrag = RNIL;
+}//Dbacc::seizeFragrec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_FS_CONNECT_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeFsConnectRec(Signal* signal)
+{
+ fsConnectptr.i = cfsFirstfreeconnect;
+ ptrCheckGuard(fsConnectptr, cfsConnectsize, fsConnectrec);
+ cfsFirstfreeconnect = fsConnectptr.p->fsNext;
+ fsConnectptr.p->fsNext = RNIL;
+ fsConnectptr.p->fsState = WAIT_NOTHING;
+}//Dbacc::seizeFsConnectRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_FS_OP_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeFsOpRec(Signal* signal)
+{
+ fsOpptr.i = cfsFirstfreeop;
+ ptrCheckGuard(fsOpptr, cfsOpsize, fsOprec);
+ cfsFirstfreeop = fsOpptr.p->fsOpnext;
+ fsOpptr.p->fsOpnext = RNIL;
+}//Dbacc::seizeFsOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_LCP_CONNECT_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeLcpConnectRec(Signal* signal)
+{
+ lcpConnectptr.i = cfirstfreelcpConnect;
+ ptrCheckGuard(lcpConnectptr, clcpConnectsize, lcpConnectrec);
+ cfirstfreelcpConnect = lcpConnectptr.p->nextLcpConn;
+ lcpConnectptr.p->nextLcpConn = RNIL;
+}//Dbacc::seizeLcpConnectRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_OP_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeOpRec(Signal* signal)
+{
+ operationRecPtr.i = cfreeopRec;
+ ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
+ cfreeopRec = operationRecPtr.p->nextOp; /* UPDATE FREE LIST OF OP RECORDS */
+ /* PUTS OPERTION RECORD PTR IN THE LIST */
+ /* OF OPERATION IN CONNECTION RECORD */
+ operationRecPtr.p->nextOp = RNIL;
+}//Dbacc::seizeOpRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE OVERFLOW RECORD */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeOverRec(Signal* signal) {
+ sorOverflowRecPtr.i = cfirstfreeoverrec;
+ ptrCheckGuard(sorOverflowRecPtr, coverflowrecsize, overflowRecord);
+ cfirstfreeoverrec = sorOverflowRecPtr.p->nextfreeoverrec;
+ sorOverflowRecPtr.p->nextfreeoverrec = RNIL;
+ sorOverflowRecPtr.p->prevOverRec = RNIL;
+ sorOverflowRecPtr.p->nextOverRec = RNIL;
+}//Dbacc::seizeOverRec()
+
+
+/**
+ * A ZPAGESIZE_ERROR has occured, out of index pages
+ * Print some debug info if debug compiled
+ */
+void Dbacc::zpagesize_error(const char* where){
+ DEBUG(where << endl
+ << " ZPAGESIZE_ERROR" << endl
+ << " cfirstfreepage=" << cfirstfreepage << endl
+ << " cfreepage=" <<cfreepage<<endl
+ << " cpagesize=" <<cpagesize<<endl
+ << " cnoOfAllocatedPages="<<cnoOfAllocatedPages);
+}
+
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_PAGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizePage(Signal* signal)
+{
+ tresult = 0;
+ if (cfirstfreepage == RNIL) {
+ if (cfreepage < cpagesize) {
+ jam();
+ spPageptr.i = cfreepage;
+ ptrCheckGuard(spPageptr, cpagesize, page8);
+ cfreepage++;
+ cnoOfAllocatedPages++;
+ } else {
+ jam();
+ zpagesize_error("Dbacc::seizePage");
+ tresult = ZPAGESIZE_ERROR;
+ }//if
+ } else {
+ jam();
+ spPageptr.i = cfirstfreepage;
+ ptrCheckGuard(spPageptr, cpagesize, page8);
+ cfirstfreepage = spPageptr.p->word32[0];
+ cnoOfAllocatedPages++;
+ }//if
+}//Dbacc::seizePage()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_PAGE */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeLcpPage(Page8Ptr& regPagePtr)
+{
+ regPagePtr.i = cfirstfreeLcpPage;
+ ptrCheckGuard(regPagePtr, cpagesize, page8);
+ cfirstfreeLcpPage = regPagePtr.p->word32[0];
+}//Dbacc::seizeLcpPage()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_ROOTFRAGREC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeRootfragrec(Signal* signal)
+{
+ rootfragrecptr.i = cfirstfreerootfrag;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ cfirstfreerootfrag = rootfragrecptr.p->nextroot;
+ rootfragrecptr.p->nextroot = RNIL;
+}//Dbacc::seizeRootfragrec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_SCAN_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeScanRec(Signal* signal)
+{
+ scanPtr.i = cfirstFreeScanRec;
+ ptrCheckGuard(scanPtr, cscanRecSize, scanRec);
+ ndbrequire(scanPtr.p->scanState == ScanRec::SCAN_DISCONNECT);
+ cfirstFreeScanRec = scanPtr.p->scanNextfreerec;
+}//Dbacc::seizeScanRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEIZE_SR_VERSION_REC */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::seizeSrVerRec(Signal* signal)
+{
+ srVersionPtr.i = cfirstFreeSrVersionRec;
+ ptrCheckGuard(srVersionPtr, csrVersionRecSize, srVersionRec);
+ cfirstFreeSrVersionRec = srVersionPtr.p->nextFreeSr;
+}//Dbacc::seizeSrVerRec()
+
+/* --------------------------------------------------------------------------------- */
+/* SEND_SYSTEMERROR */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::sendSystemerror(Signal* signal)
+{
+ progError(0, 0);
+}//Dbacc::sendSystemerror()
+
+/* --------------------------------------------------------------------------------- */
+/* TAKE_REC_OUT_OF_FREE_OVERDIR */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::takeRecOutOfFreeOverdir(Signal* signal)
+{
+ OverflowRecordPtr tofoOverrecPtr;
+ if (troOverflowRecPtr.p->nextOverList != RNIL) {
+ jam();
+ tofoOverrecPtr.i = troOverflowRecPtr.p->nextOverList;
+ ptrCheckGuard(tofoOverrecPtr, coverflowrecsize, overflowRecord);
+ tofoOverrecPtr.p->prevOverList = troOverflowRecPtr.p->prevOverList;
+ }//if
+ if (troOverflowRecPtr.p->prevOverList != RNIL) {
+ jam();
+ tofoOverrecPtr.i = troOverflowRecPtr.p->prevOverList;
+ ptrCheckGuard(tofoOverrecPtr, coverflowrecsize, overflowRecord);
+ tofoOverrecPtr.p->nextOverList = troOverflowRecPtr.p->nextOverList;
+ } else {
+ jam();
+ fragrecptr.p->firstFreeDirindexRec = troOverflowRecPtr.p->nextOverList;
+ }//if
+}//Dbacc::takeRecOutOfFreeOverdir()
+
+/* --------------------------------------------------------------------------------- */
+/* TAKE_REC_OUT_OF_FREE_OVERPAGE */
+/* DESCRIPTION: AN OVERFLOW PAGE WHICH IS EMPTY HAVE TO BE TAKE OUT OF THE */
+/* FREE LIST OF OVERFLOW PAGE. BY THIS SUBROUTINE THIS LIST */
+/* WILL BE UPDATED. */
+/* --------------------------------------------------------------------------------- */
+void Dbacc::takeRecOutOfFreeOverpage(Signal* signal)
+{
+ OverflowRecordPtr tfoNextOverflowRecPtr;
+ OverflowRecordPtr tfoPrevOverflowRecPtr;
+
+ if (tfoOverflowRecPtr.p->nextOverRec != RNIL) {
+ jam();
+ tfoNextOverflowRecPtr.i = tfoOverflowRecPtr.p->nextOverRec;
+ ptrCheckGuard(tfoNextOverflowRecPtr, coverflowrecsize, overflowRecord);
+ tfoNextOverflowRecPtr.p->prevOverRec = tfoOverflowRecPtr.p->prevOverRec;
+ } else {
+ ndbrequire(fragrecptr.p->lastOverflowRec == tfoOverflowRecPtr.i);
+ jam();
+ fragrecptr.p->lastOverflowRec = tfoOverflowRecPtr.p->prevOverRec;
+ }//if
+ if (tfoOverflowRecPtr.p->prevOverRec != RNIL) {
+ jam();
+ tfoPrevOverflowRecPtr.i = tfoOverflowRecPtr.p->prevOverRec;
+ ptrCheckGuard(tfoPrevOverflowRecPtr, coverflowrecsize, overflowRecord);
+ tfoPrevOverflowRecPtr.p->nextOverRec = tfoOverflowRecPtr.p->nextOverRec;
+ } else {
+ ndbrequire(fragrecptr.p->firstOverflowRec == tfoOverflowRecPtr.i);
+ jam();
+ fragrecptr.p->firstOverflowRec = tfoOverflowRecPtr.p->nextOverRec;
+ }//if
+}//Dbacc::takeRecOutOfFreeOverpage()
+
+void
+Dbacc::reportMemoryUsage(Signal* signal, int gth){
+ signal->theData[0] = NDB_LE_MemoryUsage;
+ signal->theData[1] = gth;
+ signal->theData[2] = sizeof(* rpPageptr.p);
+ signal->theData[3] = cnoOfAllocatedPages;
+ signal->theData[4] = cpagesize;
+ signal->theData[5] = DBACC;
+ sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6, JBB);
+}
+
+void
+Dbacc::execDUMP_STATE_ORD(Signal* signal)
+{
+ DumpStateOrd * const dumpState = (DumpStateOrd *)&signal->theData[0];
+ if (dumpState->args[0] == DumpStateOrd::AccDumpOneScanRec){
+ Uint32 recordNo = RNIL;
+ if (signal->length() == 2)
+ recordNo = dumpState->args[1];
+ else
+ return;
+
+ if (recordNo >= cscanRecSize)
+ return;
+
+ scanPtr.i = recordNo;
+ ptrAss(scanPtr, scanRec);
+ infoEvent("Dbacc::ScanRec[%d]: state=%d, transid(0x%x, 0x%x)",
+ scanPtr.i, scanPtr.p->scanState,scanPtr.p->scanTrid1,
+ scanPtr.p->scanTrid2);
+ infoEvent(" timer=%d, continueBCount=%d, "
+ "activeLocalFrag=%d, root=%d, nextBucketIndex=%d",
+ scanPtr.p->scanTimer,
+ scanPtr.p->scanContinuebCounter,
+ scanPtr.p->activeLocalFrag,
+ scanPtr.p->rootPtr,
+ scanPtr.p->nextBucketIndex);
+ infoEvent(" scanNextfreerec=%d firstActOp=%d firstLockedOp=%d, "
+ "scanLastLockedOp=%d firstQOp=%d lastQOp=%d",
+ scanPtr.p->scanNextfreerec,
+ scanPtr.p->scanFirstActiveOp,
+ scanPtr.p->scanFirstLockedOp,
+ scanPtr.p->scanLastLockedOp,
+ scanPtr.p->scanFirstQueuedOp,
+ scanPtr.p->scanLastQueuedOp);
+ infoEvent(" scanUserP=%d, startNoBuck=%d, minBucketIndexToRescan=%d, "
+ "maxBucketIndexToRescan=%d",
+ scanPtr.p->scanUserptr,
+ scanPtr.p->startNoOfBuckets,
+ scanPtr.p->minBucketIndexToRescan,
+ scanPtr.p->maxBucketIndexToRescan);
+ infoEvent(" scanBucketState=%d, scanLockHeld=%d, userBlockRef=%d, "
+ "scanMask=%d scanLockMode=%d",
+ scanPtr.p->scanBucketState,
+ scanPtr.p->scanLockHeld,
+ scanPtr.p->scanUserblockref,
+ scanPtr.p->scanMask,
+ scanPtr.p->scanLockMode);
+ return;
+ }
+
+ // Dump all ScanRec(ords)
+ if (dumpState->args[0] == DumpStateOrd::AccDumpAllScanRec){
+ Uint32 recordNo = 0;
+ if (signal->length() == 1)
+ infoEvent("ACC: Dump all ScanRec - size: %d",
+ cscanRecSize);
+ else if (signal->length() == 2)
+ recordNo = dumpState->args[1];
+ else
+ return;
+
+ dumpState->args[0] = DumpStateOrd::AccDumpOneScanRec;
+ dumpState->args[1] = recordNo;
+ execDUMP_STATE_ORD(signal);
+
+ if (recordNo < cscanRecSize-1){
+ dumpState->args[0] = DumpStateOrd::AccDumpAllScanRec;
+ dumpState->args[1] = recordNo+1;
+ sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB);
+ }
+ return;
+ }
+
+ // Dump all active ScanRec(ords)
+ if (dumpState->args[0] == DumpStateOrd::AccDumpAllActiveScanRec){
+ Uint32 recordNo = 0;
+ if (signal->length() == 1)
+ infoEvent("ACC: Dump active ScanRec - size: %d",
+ cscanRecSize);
+ else if (signal->length() == 2)
+ recordNo = dumpState->args[1];
+ else
+ return;
+
+ ScanRecPtr sp;
+ sp.i = recordNo;
+ ptrAss(sp, scanRec);
+ if (sp.p->scanState != ScanRec::SCAN_DISCONNECT){
+ dumpState->args[0] = DumpStateOrd::AccDumpOneScanRec;
+ dumpState->args[1] = recordNo;
+ execDUMP_STATE_ORD(signal);
+ }
+
+ if (recordNo < cscanRecSize-1){
+ dumpState->args[0] = DumpStateOrd::AccDumpAllActiveScanRec;
+ dumpState->args[1] = recordNo+1;
+ sendSignal(reference(), GSN_DUMP_STATE_ORD, signal, 2, JBB);
+ }
+ return;
+ }
+
+ if(dumpState->args[0] == DumpStateOrd::DumpPageMemory){
+ reportMemoryUsage(signal, 0);
+ return;
+ }
+
+ if(dumpState->args[0] == DumpStateOrd::EnableUndoDelayDataWrite){
+ ndbout << "Dbacc:: delay write of datapages for table = "
+ << dumpState->args[1]<< endl;
+ c_errorInsert3000_TableId = dumpState->args[1];
+ SET_ERROR_INSERT_VALUE(3000);
+ return;
+ }
+
+ if(dumpState->args[0] == DumpStateOrd::AccDumpOneOperationRec){
+ Uint32 recordNo = RNIL;
+ if (signal->length() == 2)
+ recordNo = dumpState->args[1];
+ else
+ return;
+
+ if (recordNo >= coprecsize)
+ return;
+
+ OperationrecPtr tmpOpPtr;
+ tmpOpPtr.i = recordNo;
+ ptrAss(tmpOpPtr, operationrec);
+ infoEvent("Dbacc::operationrec[%d]: opState=%d, transid(0x%x, 0x%x)",
+ tmpOpPtr.i, tmpOpPtr.p->opState, tmpOpPtr.p->transId1,
+ tmpOpPtr.p->transId2);
+ infoEvent("elementIsforward=%d, elementPage=%d, elementPointer=%d ",
+ tmpOpPtr.p->elementIsforward, tmpOpPtr.p->elementPage,
+ tmpOpPtr.p->elementPointer);
+ infoEvent("fid=%d, fragptr=%d, hashvaluePart=%d ",
+ tmpOpPtr.p->fid, tmpOpPtr.p->fragptr,
+ tmpOpPtr.p->hashvaluePart);
+ infoEvent("hashValue=%d, insertDeleteLen=%d, keyinfoPage=%d ",
+ tmpOpPtr.p->hashValue, tmpOpPtr.p->insertDeleteLen,
+ tmpOpPtr.p->keyinfoPage);
+ infoEvent("nextLockOwnerOp=%d, nextOp=%d, nextParallelQue=%d ",
+ tmpOpPtr.p->nextLockOwnerOp, tmpOpPtr.p->nextOp,
+ tmpOpPtr.p->nextParallelQue);
+ infoEvent("nextQueOp=%d, nextSerialQue=%d, prevOp=%d ",
+ tmpOpPtr.p->nextQueOp, tmpOpPtr.p->nextSerialQue,
+ tmpOpPtr.p->prevOp);
+ infoEvent("prevLockOwnerOp=%d, prevParallelQue=%d, prevQueOp=%d ",
+ tmpOpPtr.p->prevLockOwnerOp, tmpOpPtr.p->nextParallelQue,
+ tmpOpPtr.p->prevQueOp);
+ infoEvent("prevSerialQue=%d, scanRecPtr=%d, longPagePtr=%d ",
+ tmpOpPtr.p->prevSerialQue, tmpOpPtr.p->scanRecPtr,
+ tmpOpPtr.p->longPagePtr);
+ infoEvent("transactionstate=%d, elementIsDisappeared=%d, insertIsDone=%d ",
+ tmpOpPtr.p->transactionstate, tmpOpPtr.p->elementIsDisappeared,
+ tmpOpPtr.p->insertIsDone);
+ infoEvent("lockMode=%d, lockOwner=%d, nodeType=%d ",
+ tmpOpPtr.p->lockMode, tmpOpPtr.p->lockOwner,
+ tmpOpPtr.p->nodeType);
+ infoEvent("operation=%d, opSimple=%d, dirtyRead=%d,scanBits=%d ",
+ tmpOpPtr.p->operation, tmpOpPtr.p->opSimple,
+ tmpOpPtr.p->dirtyRead, tmpOpPtr.p->scanBits);
+ return;
+ }
+
+ if(dumpState->args[0] == DumpStateOrd::AccDumpNumOpRecs){
+
+ Uint32 freeOpRecs = 0;
+ OperationrecPtr opRecPtr;
+ opRecPtr.i = cfreeopRec;
+ while (opRecPtr.i != RNIL){
+ freeOpRecs++;
+ ptrCheckGuard(opRecPtr, coprecsize, operationrec);
+ opRecPtr.i = opRecPtr.p->nextOp;
+ }
+
+ infoEvent("Dbacc::OperationRecords: num=%d, free=%d",
+ coprecsize, freeOpRecs);
+
+ return;
+ }
+ if(dumpState->args[0] == DumpStateOrd::AccDumpFreeOpRecs){
+
+ OperationrecPtr opRecPtr;
+ opRecPtr.i = cfreeopRec;
+ while (opRecPtr.i != RNIL){
+
+ dumpState->args[0] = DumpStateOrd::AccDumpOneOperationRec;
+ dumpState->args[1] = opRecPtr.i;
+ execDUMP_STATE_ORD(signal);
+
+ ptrCheckGuard(opRecPtr, coprecsize, operationrec);
+ opRecPtr.i = opRecPtr.p->nextOp;
+ }
+
+
+ return;
+ }
+
+ if(dumpState->args[0] == DumpStateOrd::AccDumpNotFreeOpRecs){
+ Uint32 recordStart = RNIL;
+ if (signal->length() == 2)
+ recordStart = dumpState->args[1];
+ else
+ return;
+
+ if (recordStart >= coprecsize)
+ return;
+
+ for (Uint32 i = recordStart; i < coprecsize; i++){
+
+ bool inFreeList = false;
+ OperationrecPtr opRecPtr;
+ opRecPtr.i = cfreeopRec;
+ while (opRecPtr.i != RNIL){
+ if (opRecPtr.i == i){
+ inFreeList = true;
+ break;
+ }
+ ptrCheckGuard(opRecPtr, coprecsize, operationrec);
+ opRecPtr.i = opRecPtr.p->nextOp;
+ }
+ if (inFreeList == false){
+ dumpState->args[0] = DumpStateOrd::AccDumpOneOperationRec;
+ dumpState->args[1] = i;
+ execDUMP_STATE_ORD(signal);
+ }
+ }
+ return;
+ }
+
+#if 0
+ if (type == 100) {
+ RelTabMemReq * const req = (RelTabMemReq *)signal->getDataPtrSend();
+ req->primaryTableId = 2;
+ req->secondaryTableId = RNIL;
+ req->userPtr = 2;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_REL_TABMEMREQ, signal,
+ RelTabMemReq::SignalLength, JBB);
+ return;
+ }//if
+ if (type == 101) {
+ RelTabMemReq * const req = (RelTabMemReq *)signal->getDataPtrSend();
+ req->primaryTableId = 4;
+ req->secondaryTableId = 5;
+ req->userPtr = 4;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_REL_TABMEMREQ, signal,
+ RelTabMemReq::SignalLength, JBB);
+ return;
+ }//if
+ if (type == 102) {
+ RelTabMemReq * const req = (RelTabMemReq *)signal->getDataPtrSend();
+ req->primaryTableId = 6;
+ req->secondaryTableId = 8;
+ req->userPtr = 6;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_REL_TABMEMREQ, signal,
+ RelTabMemReq::SignalLength, JBB);
+ return;
+ }//if
+ if (type == 103) {
+ DropTabFileReq * const req = (DropTabFileReq *)signal->getDataPtrSend();
+ req->primaryTableId = 2;
+ req->secondaryTableId = RNIL;
+ req->userPtr = 2;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_DROP_TABFILEREQ, signal,
+ DropTabFileReq::SignalLength, JBB);
+ return;
+ }//if
+ if (type == 104) {
+ DropTabFileReq * const req = (DropTabFileReq *)signal->getDataPtrSend();
+ req->primaryTableId = 4;
+ req->secondaryTableId = 5;
+ req->userPtr = 4;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_DROP_TABFILEREQ, signal,
+ DropTabFileReq::SignalLength, JBB);
+ return;
+ }//if
+ if (type == 105) {
+ DropTabFileReq * const req = (DropTabFileReq *)signal->getDataPtrSend();
+ req->primaryTableId = 6;
+ req->secondaryTableId = 8;
+ req->userPtr = 6;
+ req->userRef = DBDICT_REF;
+ sendSignal(cownBlockref, GSN_DROP_TABFILEREQ, signal,
+ DropTabFileReq::SignalLength, JBB);
+ return;
+ }//if
+#endif
+}//Dbacc::execDUMP_STATE_ORD()
+
+void Dbacc::execSET_VAR_REQ(Signal* signal)
+{
+#if 0
+ SetVarReq* const setVarReq = (SetVarReq*)&signal->theData[0];
+ ConfigParamId var = setVarReq->variable();
+ int val = setVarReq->value();
+
+
+ switch (var) {
+
+ case NoOfDiskPagesToDiskAfterRestartACC:
+ clblPagesPerTick = val;
+ sendSignal(CMVMI_REF, GSN_SET_VAR_CONF, signal, 1, JBB);
+ break;
+
+ case NoOfDiskPagesToDiskDuringRestartACC:
+ // 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()
+
+void
+Dbacc::execREAD_PSUEDO_REQ(Signal* signal){
+ jamEntry();
+ fragrecptr.i = signal->theData[0];
+ Uint32 attrId = signal->theData[1];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ Uint64 tmp;
+ switch(attrId){
+ case AttributeHeader::ROW_COUNT:
+ tmp = rootfragrecptr.p->noOfElements;
+ break;
+ case AttributeHeader::COMMIT_COUNT:
+ tmp = rootfragrecptr.p->m_commit_count;
+ break;
+ default:
+ tmp = 0;
+ }
+ memcpy(signal->theData, &tmp, 8); /* must be memcpy, gives strange results on
+ * ithanium gcc (GCC) 3.4.1 smp linux 2.4
+ * otherwise
+ */
+ // Uint32 * src = (Uint32*)&tmp;
+ // signal->theData[0] = src[0];
+ // signal->theData[1] = src[1];
+}
+