diff options
Diffstat (limited to 'storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp')
-rw-r--r-- | storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp | 11884 |
1 files changed, 11884 insertions, 0 deletions
diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp new file mode 100644 index 00000000000..4bc5b127a8f --- /dev/null +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -0,0 +1,11884 @@ +/* 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 */ + +#include <ndb_global.h> +#include <my_sys.h> + +#define DBDICT_C +#include "Dbdict.hpp" + +#include <ndb_limits.h> +#include <NdbOut.hpp> +#include <Properties.hpp> +#include <Configuration.hpp> +#include <SectionReader.hpp> +#include <SimpleProperties.hpp> +#include <AttributeHeader.hpp> +#include <signaldata/DictSchemaInfo.hpp> +#include <signaldata/DictTabInfo.hpp> +#include <signaldata/DropTabFile.hpp> + +#include <signaldata/EventReport.hpp> +#include <signaldata/FsCloseReq.hpp> +#include <signaldata/FsConf.hpp> +#include <signaldata/FsOpenReq.hpp> +#include <signaldata/FsReadWriteReq.hpp> +#include <signaldata/FsRef.hpp> +#include <signaldata/GetTabInfo.hpp> +#include <signaldata/GetTableId.hpp> +#include <signaldata/HotSpareRep.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> +#include <signaldata/ReadNodesConf.hpp> +#include <signaldata/RelTabMem.hpp> +#include <signaldata/WaitGCP.hpp> +#include <signaldata/ListTables.hpp> + +#include <signaldata/CreateTrig.hpp> +#include <signaldata/AlterTrig.hpp> +#include <signaldata/DropTrig.hpp> +#include <signaldata/CreateIndx.hpp> +#include <signaldata/DropIndx.hpp> +#include <signaldata/BuildIndx.hpp> + +#include <signaldata/CreateEvnt.hpp> +#include <signaldata/UtilPrepare.hpp> +#include <signaldata/UtilExecute.hpp> +#include <signaldata/UtilRelease.hpp> +#include <signaldata/SumaImpl.hpp> +#include <GrepError.hpp> +//#include <signaldata/DropEvnt.hpp> + +#include <signaldata/LqhFrag.hpp> + +#include <signaldata/DiAddTab.hpp> +#include <signaldata/DihStartTab.hpp> + +#include <signaldata/DropTable.hpp> +#include <signaldata/DropTab.hpp> +#include <signaldata/PrepDropTab.hpp> + +#include <signaldata/CreateTable.hpp> +#include <signaldata/AlterTable.hpp> +#include <signaldata/AlterTab.hpp> +#include <signaldata/CreateFragmentation.hpp> +#include <signaldata/CreateTab.hpp> +#include <NdbSleep.h> + +#define ZNOT_FOUND 626 +#define ZALREADYEXIST 630 + +//#define EVENT_PH2_DEBUG +//#define EVENT_PH3_DEBUG +//#define EVENT_DEBUG + +#define EVENT_TRACE \ +// ndbout_c("Event debug trace: File: %s Line: %u", __FILE__, __LINE__) + +#define DIV(x,y) (((x)+(y)-1)/(y)) +#include <ndb_version.h> + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: GENERAL MODULE -------------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains general stuff. Mostly debug signals and */ +/* general signals that go into a specific module after checking a */ +/* state variable. Also general subroutines used by many. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// This signal is used to dump states of various variables in the +// block by command. +/* ---------------------------------------------------------------- */ +void +Dbdict::execDUMP_STATE_ORD(Signal* signal) +{ + jamEntry(); + +#ifdef VM_TRACE + if(signal->theData[0] == 1222){ + const Uint32 tab = signal->theData[1]; + PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); + req->senderRef = reference(); + req->senderData = 1222; + req->tableId = tab; + sendSignal(DBLQH_REF, GSN_PREP_DROP_TAB_REQ, signal, + PrepDropTabReq::SignalLength, JBB); + } + + if(signal->theData[0] == 1223){ + const Uint32 tab = signal->theData[1]; + PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); + req->senderRef = reference(); + req->senderData = 1222; + req->tableId = tab; + sendSignal(DBTC_REF, GSN_PREP_DROP_TAB_REQ, signal, + PrepDropTabReq::SignalLength, JBB); + } + + if(signal->theData[0] == 1224){ + const Uint32 tab = signal->theData[1]; + PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr(); + req->senderRef = reference(); + req->senderData = 1222; + req->tableId = tab; + sendSignal(DBDIH_REF, GSN_PREP_DROP_TAB_REQ, signal, + PrepDropTabReq::SignalLength, JBB); + } + + if(signal->theData[0] == 1225){ + const Uint32 tab = signal->theData[1]; + const Uint32 ver = signal->theData[2]; + TableRecordPtr tabRecPtr; + c_tableRecordPool.getPtr(tabRecPtr, tab); + DropTableReq * req = (DropTableReq*)signal->getDataPtr(); + req->senderData = 1225; + req->senderRef = numberToRef(1,1); + req->tableId = tab; + req->tableVersion = tabRecPtr.p->tableVersion + ver; + sendSignal(DBDICT_REF, GSN_DROP_TABLE_REQ, signal, + DropTableReq::SignalLength, JBB); + } +#endif + + return; +}//Dbdict::execDUMP_STATE_ORD() + +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ +// CONTINUEB is used when a real-time break is needed for long +// processes. +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ +void Dbdict::execCONTINUEB(Signal* signal) +{ + jamEntry(); + switch (signal->theData[0]) { + case ZPACK_TABLE_INTO_PAGES : + jam(); + packTableIntoPages(signal, signal->theData[1], signal->theData[2]); + break; + + case ZSEND_GET_TAB_RESPONSE : + jam(); + sendGetTabResponse(signal); + break; + + default : + ndbrequire(false); + break; + }//switch + return; +}//execCONTINUEB() + +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ +// Routine to handle pack table into pages. +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ + +void Dbdict::packTableIntoPages(Signal* signal, Uint32 tableId, Uint32 pageId) +{ + + PageRecordPtr pagePtr; + TableRecordPtr tablePtr; + c_pageRecordArray.getPtr(pagePtr, pageId); + + memset(&pagePtr.p->word[0], 0, 4 * ZPAGE_HEADER_SIZE); + c_tableRecordPool.getPtr(tablePtr, tableId); + LinearWriter w(&pagePtr.p->word[ZPAGE_HEADER_SIZE], + 8 * ZSIZE_OF_PAGES_IN_WORDS); + + w.first(); + packTableIntoPagesImpl(w, tablePtr, signal); + + Uint32 wordsOfTable = w.getWordsUsed(); + Uint32 pagesUsed = + DIV(wordsOfTable + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS); + pagePtr.p->word[ZPOS_CHECKSUM] = + computeChecksum(&pagePtr.p->word[0], pagesUsed * ZSIZE_OF_PAGES_IN_WORDS); + + switch (c_packTable.m_state) { + case PackTable::PTS_IDLE: + case PackTable::PTS_ADD_TABLE_MASTER: + case PackTable::PTS_ADD_TABLE_SLAVE: + case PackTable::PTS_RESTART: + ndbrequire(false); + break; + case PackTable::PTS_GET_TAB: + jam(); + c_retrieveRecord.retrievedNoOfPages = pagesUsed; + c_retrieveRecord.retrievedNoOfWords = wordsOfTable; + sendGetTabResponse(signal); + return; + break; + }//switch + ndbrequire(false); + return; +}//packTableIntoPages() + +void +Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w, + TableRecordPtr tablePtr, + Signal* signal){ + + w.add(DictTabInfo::TableName, tablePtr.p->tableName); + w.add(DictTabInfo::TableId, tablePtr.i); +#ifdef HAVE_TABLE_REORG + w.add(DictTabInfo::SecondTableId, tablePtr.p->secondTable); +#else + w.add(DictTabInfo::SecondTableId, (Uint32)0); +#endif + w.add(DictTabInfo::TableVersion, tablePtr.p->tableVersion); + w.add(DictTabInfo::NoOfKeyAttr, tablePtr.p->noOfPrimkey); + w.add(DictTabInfo::NoOfAttributes, tablePtr.p->noOfAttributes); + w.add(DictTabInfo::NoOfNullable, tablePtr.p->noOfNullAttr); + w.add(DictTabInfo::NoOfVariable, (Uint32)0); + w.add(DictTabInfo::KeyLength, tablePtr.p->tupKeyLength); + + w.add(DictTabInfo::TableLoggedFlag, tablePtr.p->storedTable); + w.add(DictTabInfo::MinLoadFactor, tablePtr.p->minLoadFactor); + w.add(DictTabInfo::MaxLoadFactor, tablePtr.p->maxLoadFactor); + w.add(DictTabInfo::TableKValue, tablePtr.p->kValue); + w.add(DictTabInfo::FragmentTypeVal, tablePtr.p->fragmentType); + w.add(DictTabInfo::TableTypeVal, tablePtr.p->tableType); + + if(!signal) + { + w.add(DictTabInfo::FragmentCount, tablePtr.p->fragmentCount); + } + else + { + Uint32 * theData = signal->getDataPtrSend(); + CreateFragmentationReq * const req = (CreateFragmentationReq*)theData; + req->senderRef = 0; + req->senderData = RNIL; + req->fragmentationType = tablePtr.p->fragmentType; + req->noOfFragments = 0; + req->fragmentNode = 0; + req->primaryTableId = tablePtr.i; + EXECUTE_DIRECT(DBDIH, GSN_CREATE_FRAGMENTATION_REQ, signal, + CreateFragmentationReq::SignalLength); + if(signal->theData[0] == 0) + { + Uint16 *data = (Uint16*)&signal->theData[25]; + Uint32 count = 2 + data[0] * data[1]; + w.add(DictTabInfo::FragmentDataLen, 2*count); + w.add(DictTabInfo::FragmentData, data, 2*count); + } + } + + if (tablePtr.p->primaryTableId != RNIL){ + TableRecordPtr primTab; + c_tableRecordPool.getPtr(primTab, tablePtr.p->primaryTableId); + w.add(DictTabInfo::PrimaryTable, primTab.p->tableName); + w.add(DictTabInfo::PrimaryTableId, tablePtr.p->primaryTableId); + w.add(DictTabInfo::IndexState, tablePtr.p->indexState); + w.add(DictTabInfo::InsertTriggerId, tablePtr.p->insertTriggerId); + w.add(DictTabInfo::UpdateTriggerId, tablePtr.p->updateTriggerId); + w.add(DictTabInfo::DeleteTriggerId, tablePtr.p->deleteTriggerId); + w.add(DictTabInfo::CustomTriggerId, tablePtr.p->customTriggerId); + } + w.add(DictTabInfo::FrmLen, tablePtr.p->frmLen); + w.add(DictTabInfo::FrmData, tablePtr.p->frmData, tablePtr.p->frmLen); + + Uint32 nextAttribute = tablePtr.p->firstAttribute; + AttributeRecordPtr attrPtr; + do { + jam(); + c_attributeRecordPool.getPtr(attrPtr, nextAttribute); + + w.add(DictTabInfo::AttributeName, attrPtr.p->attributeName); + w.add(DictTabInfo::AttributeId, attrPtr.p->attributeId); + w.add(DictTabInfo::AttributeKeyFlag, attrPtr.p->tupleKey > 0); + + const Uint32 desc = attrPtr.p->attributeDescriptor; + const Uint32 attrType = AttributeDescriptor::getType(desc); + const Uint32 attrSize = AttributeDescriptor::getSize(desc); + const Uint32 arraySize = AttributeDescriptor::getArraySize(desc); + const Uint32 nullable = AttributeDescriptor::getNullable(desc); + const Uint32 DKey = AttributeDescriptor::getDKey(desc); + + // AttributeType deprecated + w.add(DictTabInfo::AttributeSize, attrSize); + w.add(DictTabInfo::AttributeArraySize, arraySize); + w.add(DictTabInfo::AttributeNullableFlag, nullable); + w.add(DictTabInfo::AttributeDKey, DKey); + w.add(DictTabInfo::AttributeExtType, attrType); + w.add(DictTabInfo::AttributeExtPrecision, attrPtr.p->extPrecision); + w.add(DictTabInfo::AttributeExtScale, attrPtr.p->extScale); + w.add(DictTabInfo::AttributeExtLength, attrPtr.p->extLength); + w.add(DictTabInfo::AttributeAutoIncrement, + (Uint32)attrPtr.p->autoIncrement); + w.add(DictTabInfo::AttributeDefaultValue, attrPtr.p->defaultValue); + + w.add(DictTabInfo::AttributeEnd, 1); + nextAttribute = attrPtr.p->nextAttrInTable; + } while (nextAttribute != RNIL); + + w.add(DictTabInfo::TableEnd, 1); +} + +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ +// The routines to handle responses from file system. +/* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- */ +// A file was successfully closed. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSCLOSECONF(Signal* signal) +{ + FsConnectRecordPtr fsPtr; + FsConf * const fsConf = (FsConf *)&signal->theData[0]; + jamEntry(); + c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer); + switch (fsPtr.p->fsState) { + case FsConnectRecord::CLOSE_WRITE_SCHEMA: + jam(); + closeWriteSchemaConf(signal, fsPtr); + break; + case FsConnectRecord::CLOSE_READ_SCHEMA: + jam(); + closeReadSchemaConf(signal, fsPtr); + break; + case FsConnectRecord::CLOSE_READ_TAB_FILE: + jam(); + closeReadTableConf(signal, fsPtr); + break; + case FsConnectRecord::CLOSE_WRITE_TAB_FILE: + jam(); + closeWriteTableConf(signal, fsPtr); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSCLOSECONF() + +/* ---------------------------------------------------------------- */ +// A close file was refused. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSCLOSEREF(Signal* signal) +{ + jamEntry(); + progError(0, 0); +}//execFSCLOSEREF() + +/* ---------------------------------------------------------------- */ +// A file was successfully opened. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSOPENCONF(Signal* signal) +{ + FsConnectRecordPtr fsPtr; + jamEntry(); + FsConf * const fsConf = (FsConf *)&signal->theData[0]; + c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer); + + Uint32 filePointer = fsConf->filePointer; + fsPtr.p->filePtr = filePointer; + switch (fsPtr.p->fsState) { + case FsConnectRecord::OPEN_WRITE_SCHEMA: + jam(); + fsPtr.p->fsState = FsConnectRecord::WRITE_SCHEMA; + writeSchemaFile(signal, filePointer, fsPtr.i); + break; + case FsConnectRecord::OPEN_READ_SCHEMA1: + jam(); + fsPtr.p->fsState = FsConnectRecord::READ_SCHEMA1; + readSchemaFile(signal, filePointer, fsPtr.i); + break; + case FsConnectRecord::OPEN_READ_SCHEMA2: + jam(); + fsPtr.p->fsState = FsConnectRecord::READ_SCHEMA2; + readSchemaFile(signal, filePointer, fsPtr.i); + break; + case FsConnectRecord::OPEN_READ_TAB_FILE1: + jam(); + fsPtr.p->fsState = FsConnectRecord::READ_TAB_FILE1; + readTableFile(signal, filePointer, fsPtr.i); + break; + case FsConnectRecord::OPEN_READ_TAB_FILE2: + jam(); + fsPtr.p->fsState = FsConnectRecord::READ_TAB_FILE2; + readTableFile(signal, filePointer, fsPtr.i); + break; + case FsConnectRecord::OPEN_WRITE_TAB_FILE: + jam(); + fsPtr.p->fsState = FsConnectRecord::WRITE_TAB_FILE; + writeTableFile(signal, filePointer, fsPtr.i); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSOPENCONF() + +/* ---------------------------------------------------------------- */ +// An open file was refused. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSOPENREF(Signal* signal) +{ + jamEntry(); + FsRef * const fsRef = (FsRef *)&signal->theData[0]; + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer); + switch (fsPtr.p->fsState) { + case FsConnectRecord::OPEN_READ_SCHEMA1: + openReadSchemaRef(signal, fsPtr); + break; + case FsConnectRecord::OPEN_READ_TAB_FILE1: + jam(); + openReadTableRef(signal, fsPtr); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSOPENREF() + +/* ---------------------------------------------------------------- */ +// A file was successfully read. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSREADCONF(Signal* signal) +{ + jamEntry(); + FsConf * const fsConf = (FsConf *)&signal->theData[0]; + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer); + switch (fsPtr.p->fsState) { + case FsConnectRecord::READ_SCHEMA1: + case FsConnectRecord::READ_SCHEMA2: + readSchemaConf(signal ,fsPtr); + break; + case FsConnectRecord::READ_TAB_FILE1: + case FsConnectRecord::READ_TAB_FILE2: + jam(); + readTableConf(signal ,fsPtr); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSREADCONF() + +/* ---------------------------------------------------------------- */ +// A read file was refused. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSREADREF(Signal* signal) +{ + jamEntry(); + FsRef * const fsRef = (FsRef *)&signal->theData[0]; + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer); + switch (fsPtr.p->fsState) { + case FsConnectRecord::READ_SCHEMA1: + readSchemaRef(signal, fsPtr); + break; + case FsConnectRecord::READ_TAB_FILE1: + jam(); + readTableRef(signal, fsPtr); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSREADREF() + +/* ---------------------------------------------------------------- */ +// A file was successfully written. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSWRITECONF(Signal* signal) +{ + FsConf * const fsConf = (FsConf *)&signal->theData[0]; + FsConnectRecordPtr fsPtr; + jamEntry(); + c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer); + switch (fsPtr.p->fsState) { + case FsConnectRecord::WRITE_TAB_FILE: + writeTableConf(signal, fsPtr); + break; + case FsConnectRecord::WRITE_SCHEMA: + jam(); + writeSchemaConf(signal, fsPtr); + break; + default: + jamLine((fsPtr.p->fsState & 0xFFF)); + ndbrequire(false); + break; + }//switch +}//execFSWRITECONF() + +/* ---------------------------------------------------------------- */ +// A write file was refused. +/* ---------------------------------------------------------------- */ +void Dbdict::execFSWRITEREF(Signal* signal) +{ + jamEntry(); + progError(0, 0); +}//execFSWRITEREF() + +/* ---------------------------------------------------------------- */ +// Routines to handle Read/Write of Table Files +/* ---------------------------------------------------------------- */ +void +Dbdict::writeTableFile(Signal* signal, Uint32 tableId, + SegmentedSectionPtr tabInfoPtr, Callback* callback){ + + ndbrequire(c_writeTableRecord.tableWriteState == WriteTableRecord::IDLE); + + Uint32 sz = tabInfoPtr.sz + ZPAGE_HEADER_SIZE; + + c_writeTableRecord.noOfPages = DIV(sz, ZSIZE_OF_PAGES_IN_WORDS); + c_writeTableRecord.tableWriteState = WriteTableRecord::TWR_CALLBACK; + c_writeTableRecord.m_callback = * callback; + + c_writeTableRecord.pageId = 0; + ndbrequire(c_writeTableRecord.noOfPages < 8); + + PageRecordPtr pageRecPtr; + c_pageRecordArray.getPtr(pageRecPtr, c_writeTableRecord.pageId); + copy(&pageRecPtr.p->word[ZPAGE_HEADER_SIZE], tabInfoPtr); + + memset(&pageRecPtr.p->word[0], 0, 4 * ZPAGE_HEADER_SIZE); + pageRecPtr.p->word[ZPOS_CHECKSUM] = + computeChecksum(&pageRecPtr.p->word[0], + c_writeTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS); + + startWriteTableFile(signal, tableId); + +} + +void Dbdict::startWriteTableFile(Signal* signal, Uint32 tableId) +{ + FsConnectRecordPtr fsPtr; + c_writeTableRecord.tableId = tableId; + c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord()); + fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_TAB_FILE; + openTableFile(signal, 0, fsPtr.i, tableId, true); + c_writeTableRecord.noOfTableFilesHandled = 0; +}//Dbdict::startWriteTableFile() + +void Dbdict::openTableFile(Signal* signal, + Uint32 fileNo, + Uint32 fsConPtr, + Uint32 tableId, + bool writeFlag) +{ + TableRecordPtr tablePtr; + FsOpenReq * const fsOpenReq = (FsOpenReq *)&signal->theData[0]; + c_tableRecordPool.getPtr(tablePtr, tableId); + + fsOpenReq->userReference = reference(); + fsOpenReq->userPointer = fsConPtr; + if (writeFlag) { + jam(); + fsOpenReq->fileFlags = + FsOpenReq::OM_WRITEONLY | + FsOpenReq::OM_TRUNCATE | + FsOpenReq::OM_CREATE | + FsOpenReq::OM_SYNC; + } else { + jam(); + fsOpenReq->fileFlags = FsOpenReq::OM_READONLY; + }//if + ndbrequire(tablePtr.p->tableVersion < ZNIL); + fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes + FsOpenReq::setVersion(fsOpenReq->fileNumber, 1); + FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_TABLELIST); + FsOpenReq::v1_setDisk(fsOpenReq->fileNumber, (fileNo + 1)); + FsOpenReq::v1_setTable(fsOpenReq->fileNumber, tableId); + FsOpenReq::v1_setFragment(fsOpenReq->fileNumber, (Uint32)-1); + FsOpenReq::v1_setS(fsOpenReq->fileNumber, tablePtr.p->tableVersion); + FsOpenReq::v1_setP(fsOpenReq->fileNumber, 255); +/* ---------------------------------------------------------------- */ +// File name : D1/DBDICT/T0/S1.TableList +// D1 means Disk 1 (set by fileNo + 1) +// T0 means table id = 0 +// S1 means tableVersion 1 +// TableList indicates that this is a file for a table description. +/* ---------------------------------------------------------------- */ + sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA); +}//openTableFile() + +void Dbdict::writeTableFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) +{ + FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0]; + + fsRWReq->filePointer = filePtr; + fsRWReq->userReference = reference(); + fsRWReq->userPointer = fsConPtr; + fsRWReq->operationFlag = 0; // Initialise before bit changes + FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 1); + FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, + FsReadWriteReq::fsFormatArrayOfPages); + fsRWReq->varIndex = ZALLOCATE; + fsRWReq->numberOfPages = c_writeTableRecord.noOfPages; + fsRWReq->data.arrayOfPages.varIndex = c_writeTableRecord.pageId; + fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0 + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); +}//writeTableFile() + +void Dbdict::writeTableConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::CLOSE_WRITE_TAB_FILE; + closeFile(signal, fsPtr.p->filePtr, fsPtr.i); + return; +}//Dbdict::writeTableConf() + +void Dbdict::closeWriteTableConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + c_writeTableRecord.noOfTableFilesHandled++; + if (c_writeTableRecord.noOfTableFilesHandled < 2) { + jam(); + fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_TAB_FILE; + openTableFile(signal, 1, fsPtr.i, c_writeTableRecord.tableId, true); + return; + } + ndbrequire(c_writeTableRecord.noOfTableFilesHandled == 2); + c_fsConnectRecordPool.release(fsPtr); + WriteTableRecord::TableWriteState state = c_writeTableRecord.tableWriteState; + c_writeTableRecord.tableWriteState = WriteTableRecord::IDLE; + switch (state) { + case WriteTableRecord::IDLE: + case WriteTableRecord::WRITE_ADD_TABLE_MASTER : + case WriteTableRecord::WRITE_ADD_TABLE_SLAVE : + case WriteTableRecord::WRITE_RESTART_FROM_MASTER : + case WriteTableRecord::WRITE_RESTART_FROM_OWN : + ndbrequire(false); + break; + case WriteTableRecord::TWR_CALLBACK: + jam(); + execute(signal, c_writeTableRecord.m_callback, 0); + return; + } + ndbrequire(false); +}//Dbdict::closeWriteTableConf() + +void Dbdict::startReadTableFile(Signal* signal, Uint32 tableId) +{ + //globalSignalLoggers.log(number(), "startReadTableFile"); + ndbrequire(!c_readTableRecord.inUse); + + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord()); + c_readTableRecord.inUse = true; + c_readTableRecord.tableId = tableId; + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE1; + openTableFile(signal, 0, fsPtr.i, tableId, false); +}//Dbdict::startReadTableFile() + +void Dbdict::openReadTableRef(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE2; + openTableFile(signal, 1, fsPtr.i, c_readTableRecord.tableId, false); + return; +}//Dbdict::openReadTableConf() + +void Dbdict::readTableFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) +{ + FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0]; + + fsRWReq->filePointer = filePtr; + fsRWReq->userReference = reference(); + fsRWReq->userPointer = fsConPtr; + fsRWReq->operationFlag = 0; // Initialise before bit changes + FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 0); + FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, + FsReadWriteReq::fsFormatArrayOfPages); + fsRWReq->varIndex = ZALLOCATE; + fsRWReq->numberOfPages = c_readTableRecord.noOfPages; + fsRWReq->data.arrayOfPages.varIndex = c_readTableRecord.pageId; + fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0 + sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); +}//readTableFile() + +void Dbdict::readTableConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + /* ---------------------------------------------------------------- */ + // Verify the data read from disk + /* ---------------------------------------------------------------- */ + bool crashInd; + if (fsPtr.p->fsState == FsConnectRecord::READ_TAB_FILE1) { + jam(); + crashInd = false; + } else { + jam(); + crashInd = true; + }//if + + PageRecordPtr tmpPagePtr; + c_pageRecordArray.getPtr(tmpPagePtr, c_readTableRecord.pageId); + Uint32 sz = c_readTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS; + Uint32 chk = computeChecksum((const Uint32*)tmpPagePtr.p, sz); + + ndbrequire((chk == 0) || !crashInd); + if(chk != 0){ + jam(); + ndbrequire(fsPtr.p->fsState == FsConnectRecord::READ_TAB_FILE1); + readTableRef(signal, fsPtr); + return; + }//if + + fsPtr.p->fsState = FsConnectRecord::CLOSE_READ_TAB_FILE; + closeFile(signal, fsPtr.p->filePtr, fsPtr.i); + return; +}//Dbdict::readTableConf() + +void Dbdict::readTableRef(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE2; + openTableFile(signal, 1, fsPtr.i, c_readTableRecord.tableId, false); + return; +}//Dbdict::readTableRef() + +void Dbdict::closeReadTableConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + c_fsConnectRecordPool.release(fsPtr); + c_readTableRecord.inUse = false; + + execute(signal, c_readTableRecord.m_callback, 0); + return; +}//Dbdict::closeReadTableConf() + +/* ---------------------------------------------------------------- */ +// Routines to handle Read/Write of Schema Files +/* ---------------------------------------------------------------- */ +void +Dbdict::updateSchemaState(Signal* signal, Uint32 tableId, + SchemaFile::TableEntry* te, Callback* callback){ + + jam(); + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + ndbrequire(tableId < c_tableRecordPool.getSize()); + SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tableId); + + SchemaFile::TableState newState = + (SchemaFile::TableState)te->m_tableState; + SchemaFile::TableState oldState = + (SchemaFile::TableState)tableEntry->m_tableState; + + Uint32 newVersion = te->m_tableVersion; + Uint32 oldVersion = tableEntry->m_tableVersion; + + bool ok = false; + switch(newState){ + case SchemaFile::ADD_STARTED: + jam(); + ok = true; + ndbrequire((oldVersion + 1) == newVersion); + ndbrequire(oldState == SchemaFile::INIT || + oldState == SchemaFile::DROP_TABLE_COMMITTED); + break; + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + ok = true; + ndbrequire(newVersion == oldVersion); + ndbrequire(oldState == SchemaFile::ADD_STARTED); + break; + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + ok = true; + ndbrequire((oldVersion + 1) == newVersion); + ndbrequire(oldState == SchemaFile::TABLE_ADD_COMMITTED || + oldState == SchemaFile::ALTER_TABLE_COMMITTED); + break; + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + ok = true; + ndbrequire(false); + break; + case SchemaFile::INIT: + jam(); + ok = true; + ndbrequire((oldState == SchemaFile::ADD_STARTED)); + }//if + ndbrequire(ok); + + * tableEntry = * te; + computeChecksum((SchemaFile*)pagePtr.p); + + ndbrequire(c_writeSchemaRecord.inUse == false); + c_writeSchemaRecord.inUse = true; + + c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage; + c_writeSchemaRecord.m_callback = * callback; + + startWriteSchemaFile(signal); +} + +void Dbdict::startWriteSchemaFile(Signal* signal) +{ + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord()); + fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_SCHEMA; + openSchemaFile(signal, 0, fsPtr.i, true); + c_writeSchemaRecord.noOfSchemaFilesHandled = 0; +}//Dbdict::startWriteSchemaFile() + +void Dbdict::openSchemaFile(Signal* signal, + Uint32 fileNo, + Uint32 fsConPtr, + bool writeFlag) +{ + FsOpenReq * const fsOpenReq = (FsOpenReq *)&signal->theData[0]; + fsOpenReq->userReference = reference(); + fsOpenReq->userPointer = fsConPtr; + if (writeFlag) { + jam(); + fsOpenReq->fileFlags = + FsOpenReq::OM_WRITEONLY | + FsOpenReq::OM_TRUNCATE | + FsOpenReq::OM_CREATE | + FsOpenReq::OM_SYNC; + } else { + jam(); + fsOpenReq->fileFlags = FsOpenReq::OM_READONLY; + }//if + fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes + FsOpenReq::setVersion(fsOpenReq->fileNumber, 1); + FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_SCHEMALOG); + FsOpenReq::v1_setDisk(fsOpenReq->fileNumber, (fileNo + 1)); + FsOpenReq::v1_setTable(fsOpenReq->fileNumber, (Uint32)-1); + FsOpenReq::v1_setFragment(fsOpenReq->fileNumber, (Uint32)-1); + FsOpenReq::v1_setS(fsOpenReq->fileNumber, (Uint32)-1); + FsOpenReq::v1_setP(fsOpenReq->fileNumber, 0); +/* ---------------------------------------------------------------- */ +// File name : D1/DBDICT/P0.SchemaLog +// D1 means Disk 1 (set by fileNo + 1). Writes to both D1 and D2 +// SchemaLog indicates that this is a file giving a list of current tables. +/* ---------------------------------------------------------------- */ + sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA); +}//openSchemaFile() + +void Dbdict::writeSchemaFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) +{ + FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0]; + + fsRWReq->filePointer = filePtr; + fsRWReq->userReference = reference(); + fsRWReq->userPointer = fsConPtr; + fsRWReq->operationFlag = 0; // Initialise before bit changes + FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 1); + FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, + FsReadWriteReq::fsFormatArrayOfPages); + fsRWReq->varIndex = ZALLOCATE; + fsRWReq->numberOfPages = 1; +// Write from memory page + fsRWReq->data.arrayOfPages.varIndex = c_writeSchemaRecord.pageId; + fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0 + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA); +}//writeSchemaFile() + +void Dbdict::writeSchemaConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::CLOSE_WRITE_SCHEMA; + closeFile(signal, fsPtr.p->filePtr, fsPtr.i); + return; +}//Dbdict::writeSchemaConf() + +void Dbdict::closeFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) +{ + FsCloseReq * const fsCloseReq = (FsCloseReq *)&signal->theData[0]; + fsCloseReq->filePointer = filePtr; + fsCloseReq->userReference = reference(); + fsCloseReq->userPointer = fsConPtr; + FsCloseReq::setRemoveFileFlag(fsCloseReq->fileFlag, false); + sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, FsCloseReq::SignalLength, JBA); + return; +}//closeFile() + +void Dbdict::closeWriteSchemaConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + c_writeSchemaRecord.noOfSchemaFilesHandled++; + if (c_writeSchemaRecord.noOfSchemaFilesHandled < 2) { + jam(); + fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_SCHEMA; + openSchemaFile(signal, 1, fsPtr.i, true); + return; + } + ndbrequire(c_writeSchemaRecord.noOfSchemaFilesHandled == 2); + + c_fsConnectRecordPool.release(fsPtr); + + c_writeSchemaRecord.inUse = false; + execute(signal, c_writeSchemaRecord.m_callback, 0); + return; +}//Dbdict::closeWriteSchemaConf() + +void Dbdict::startReadSchemaFile(Signal* signal) +{ + //globalSignalLoggers.log(number(), "startReadSchemaFile"); + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord()); + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA1; + openSchemaFile(signal, 0, fsPtr.i, false); +}//Dbdict::startReadSchemaFile() + +void Dbdict::openReadSchemaRef(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA2; + openSchemaFile(signal, 1, fsPtr.i, false); +}//Dbdict::openReadSchemaRef() + +void Dbdict::readSchemaFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) +{ + FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0]; + + fsRWReq->filePointer = filePtr; + fsRWReq->userReference = reference(); + fsRWReq->userPointer = fsConPtr; + fsRWReq->operationFlag = 0; // Initialise before bit changes + FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 0); + FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, + FsReadWriteReq::fsFormatArrayOfPages); + fsRWReq->varIndex = ZALLOCATE; + fsRWReq->numberOfPages = 1; + fsRWReq->data.arrayOfPages.varIndex = c_readSchemaRecord.pageId; + fsRWReq->data.arrayOfPages.fileOffset = 0; + sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); +}//readSchemaFile() + +void Dbdict::readSchemaConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ +/* ---------------------------------------------------------------- */ +// Verify the data read from disk +/* ---------------------------------------------------------------- */ + bool crashInd; + if (fsPtr.p->fsState == FsConnectRecord::READ_SCHEMA1) { + jam(); + crashInd = false; + } else { + jam(); + crashInd = true; + }//if + PageRecordPtr tmpPagePtr; + c_pageRecordArray.getPtr(tmpPagePtr, c_readSchemaRecord.pageId); + + Uint32 sz = ZSIZE_OF_PAGES_IN_WORDS; + Uint32 chk = computeChecksum((const Uint32*)tmpPagePtr.p, sz); + + ndbrequire((chk == 0) || !crashInd); + + if (chk != 0){ + jam(); + ndbrequire(fsPtr.p->fsState == FsConnectRecord::READ_SCHEMA1); + readSchemaRef(signal, fsPtr); + return; + }//if + fsPtr.p->fsState = FsConnectRecord::CLOSE_READ_SCHEMA; + closeFile(signal, fsPtr.p->filePtr, fsPtr.i); + return; +}//Dbdict::readSchemaConf() + +void Dbdict::readSchemaRef(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA2; + openSchemaFile(signal, 1, fsPtr.i, false); + return; +}//Dbdict::readSchemaRef() + +void Dbdict::closeReadSchemaConf(Signal* signal, + FsConnectRecordPtr fsPtr) +{ + c_fsConnectRecordPool.release(fsPtr); + ReadSchemaRecord::SchemaReadState state = c_readSchemaRecord.schemaReadState; + c_readSchemaRecord.schemaReadState = ReadSchemaRecord::IDLE; + + switch(state) { + case ReadSchemaRecord::INITIAL_READ : + jam(); + sendNDB_STTORRY(signal); + break; + + default : + ndbrequire(false); + break; + + }//switch +}//Dbdict::closeReadSchemaConf() + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: INITIALISATION MODULE ------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains initialisation of data at start/restart. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +Dbdict::Dbdict(const class Configuration & conf): + SimulatedBlock(DBDICT, conf), + c_tableRecordHash(c_tableRecordPool), + c_attributeRecordHash(c_attributeRecordPool), + c_triggerRecordHash(c_triggerRecordPool), + c_opCreateTable(c_opRecordPool), + c_opDropTable(c_opRecordPool), + c_opCreateIndex(c_opRecordPool), + c_opDropIndex(c_opRecordPool), + c_opAlterIndex(c_opRecordPool), + c_opBuildIndex(c_opRecordPool), + c_opCreateEvent(c_opRecordPool), + c_opSubEvent(c_opRecordPool), + c_opDropEvent(c_opRecordPool), + c_opSignalUtil(c_opRecordPool), + c_opCreateTrigger(c_opRecordPool), + c_opDropTrigger(c_opRecordPool), + c_opAlterTrigger(c_opRecordPool), + c_opRecordSequence(0) +{ + BLOCK_CONSTRUCTOR(Dbdict); + + const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator(); + ndbrequire(p != 0); + + ndb_mgm_get_int_parameter(p, CFG_DB_NO_TRIGGERS, &c_maxNoOfTriggers); + // Transit signals + addRecSignal(GSN_DUMP_STATE_ORD, &Dbdict::execDUMP_STATE_ORD); + addRecSignal(GSN_GET_TABINFOREQ, &Dbdict::execGET_TABINFOREQ); + addRecSignal(GSN_GET_TABLEID_REQ, &Dbdict::execGET_TABLEDID_REQ); + addRecSignal(GSN_GET_TABINFO_CONF, &Dbdict::execGET_TABINFO_CONF); + addRecSignal(GSN_CONTINUEB, &Dbdict::execCONTINUEB); + + addRecSignal(GSN_CREATE_TABLE_REQ, &Dbdict::execCREATE_TABLE_REQ); + addRecSignal(GSN_CREATE_TAB_REQ, &Dbdict::execCREATE_TAB_REQ); + addRecSignal(GSN_CREATE_TAB_REF, &Dbdict::execCREATE_TAB_REF); + addRecSignal(GSN_CREATE_TAB_CONF, &Dbdict::execCREATE_TAB_CONF); + addRecSignal(GSN_CREATE_FRAGMENTATION_REF, &Dbdict::execCREATE_FRAGMENTATION_REF); + addRecSignal(GSN_CREATE_FRAGMENTATION_CONF, &Dbdict::execCREATE_FRAGMENTATION_CONF); + addRecSignal(GSN_DIADDTABCONF, &Dbdict::execDIADDTABCONF); + addRecSignal(GSN_DIADDTABREF, &Dbdict::execDIADDTABREF); + addRecSignal(GSN_ADD_FRAGREQ, &Dbdict::execADD_FRAGREQ); + addRecSignal(GSN_TAB_COMMITCONF, &Dbdict::execTAB_COMMITCONF); + addRecSignal(GSN_TAB_COMMITREF, &Dbdict::execTAB_COMMITREF); + addRecSignal(GSN_ALTER_TABLE_REQ, &Dbdict::execALTER_TABLE_REQ); + addRecSignal(GSN_ALTER_TAB_REQ, &Dbdict::execALTER_TAB_REQ); + addRecSignal(GSN_ALTER_TAB_REF, &Dbdict::execALTER_TAB_REF); + addRecSignal(GSN_ALTER_TAB_CONF, &Dbdict::execALTER_TAB_CONF); + + // Index signals + addRecSignal(GSN_CREATE_INDX_REQ, &Dbdict::execCREATE_INDX_REQ); + addRecSignal(GSN_CREATE_INDX_CONF, &Dbdict::execCREATE_INDX_CONF); + addRecSignal(GSN_CREATE_INDX_REF, &Dbdict::execCREATE_INDX_REF); + + addRecSignal(GSN_ALTER_INDX_REQ, &Dbdict::execALTER_INDX_REQ); + addRecSignal(GSN_ALTER_INDX_CONF, &Dbdict::execALTER_INDX_CONF); + addRecSignal(GSN_ALTER_INDX_REF, &Dbdict::execALTER_INDX_REF); + + addRecSignal(GSN_CREATE_TABLE_CONF, &Dbdict::execCREATE_TABLE_CONF); + addRecSignal(GSN_CREATE_TABLE_REF, &Dbdict::execCREATE_TABLE_REF); + + addRecSignal(GSN_DROP_INDX_REQ, &Dbdict::execDROP_INDX_REQ); + addRecSignal(GSN_DROP_INDX_CONF, &Dbdict::execDROP_INDX_CONF); + addRecSignal(GSN_DROP_INDX_REF, &Dbdict::execDROP_INDX_REF); + + addRecSignal(GSN_DROP_TABLE_CONF, &Dbdict::execDROP_TABLE_CONF); + addRecSignal(GSN_DROP_TABLE_REF, &Dbdict::execDROP_TABLE_REF); + + addRecSignal(GSN_BUILDINDXREQ, &Dbdict::execBUILDINDXREQ); + addRecSignal(GSN_BUILDINDXCONF, &Dbdict::execBUILDINDXCONF); + addRecSignal(GSN_BUILDINDXREF, &Dbdict::execBUILDINDXREF); + + // Util signals + addRecSignal(GSN_UTIL_PREPARE_CONF, &Dbdict::execUTIL_PREPARE_CONF); + addRecSignal(GSN_UTIL_PREPARE_REF, &Dbdict::execUTIL_PREPARE_REF); + + addRecSignal(GSN_UTIL_EXECUTE_CONF, &Dbdict::execUTIL_EXECUTE_CONF); + addRecSignal(GSN_UTIL_EXECUTE_REF, &Dbdict::execUTIL_EXECUTE_REF); + + addRecSignal(GSN_UTIL_RELEASE_CONF, &Dbdict::execUTIL_RELEASE_CONF); + addRecSignal(GSN_UTIL_RELEASE_REF, &Dbdict::execUTIL_RELEASE_REF); + + // Event signals + addRecSignal(GSN_CREATE_EVNT_REQ, &Dbdict::execCREATE_EVNT_REQ); + addRecSignal(GSN_CREATE_EVNT_CONF, &Dbdict::execCREATE_EVNT_CONF); + addRecSignal(GSN_CREATE_EVNT_REF, &Dbdict::execCREATE_EVNT_REF); + + addRecSignal(GSN_CREATE_SUBID_CONF, &Dbdict::execCREATE_SUBID_CONF); + addRecSignal(GSN_CREATE_SUBID_REF, &Dbdict::execCREATE_SUBID_REF); + + addRecSignal(GSN_SUB_CREATE_CONF, &Dbdict::execSUB_CREATE_CONF); + addRecSignal(GSN_SUB_CREATE_REF, &Dbdict::execSUB_CREATE_REF); + + addRecSignal(GSN_SUB_START_REQ, &Dbdict::execSUB_START_REQ); + addRecSignal(GSN_SUB_START_CONF, &Dbdict::execSUB_START_CONF); + addRecSignal(GSN_SUB_START_REF, &Dbdict::execSUB_START_REF); + + addRecSignal(GSN_SUB_STOP_REQ, &Dbdict::execSUB_STOP_REQ); + addRecSignal(GSN_SUB_STOP_CONF, &Dbdict::execSUB_STOP_CONF); + addRecSignal(GSN_SUB_STOP_REF, &Dbdict::execSUB_STOP_REF); + + addRecSignal(GSN_SUB_SYNC_CONF, &Dbdict::execSUB_SYNC_CONF); + addRecSignal(GSN_SUB_SYNC_REF, &Dbdict::execSUB_SYNC_REF); + + addRecSignal(GSN_DROP_EVNT_REQ, &Dbdict::execDROP_EVNT_REQ); + + addRecSignal(GSN_SUB_REMOVE_REQ, &Dbdict::execSUB_REMOVE_REQ); + addRecSignal(GSN_SUB_REMOVE_CONF, &Dbdict::execSUB_REMOVE_CONF); + addRecSignal(GSN_SUB_REMOVE_REF, &Dbdict::execSUB_REMOVE_REF); + + // Trigger signals + addRecSignal(GSN_CREATE_TRIG_REQ, &Dbdict::execCREATE_TRIG_REQ); + addRecSignal(GSN_CREATE_TRIG_CONF, &Dbdict::execCREATE_TRIG_CONF); + addRecSignal(GSN_CREATE_TRIG_REF, &Dbdict::execCREATE_TRIG_REF); + addRecSignal(GSN_ALTER_TRIG_REQ, &Dbdict::execALTER_TRIG_REQ); + addRecSignal(GSN_ALTER_TRIG_CONF, &Dbdict::execALTER_TRIG_CONF); + addRecSignal(GSN_ALTER_TRIG_REF, &Dbdict::execALTER_TRIG_REF); + addRecSignal(GSN_DROP_TRIG_REQ, &Dbdict::execDROP_TRIG_REQ); + addRecSignal(GSN_DROP_TRIG_CONF, &Dbdict::execDROP_TRIG_CONF); + addRecSignal(GSN_DROP_TRIG_REF, &Dbdict::execDROP_TRIG_REF); + + // Received signals + addRecSignal(GSN_HOT_SPAREREP, &Dbdict::execHOT_SPAREREP); + addRecSignal(GSN_GET_SCHEMA_INFOREQ, &Dbdict::execGET_SCHEMA_INFOREQ); + addRecSignal(GSN_SCHEMA_INFO, &Dbdict::execSCHEMA_INFO); + addRecSignal(GSN_SCHEMA_INFOCONF, &Dbdict::execSCHEMA_INFOCONF); + addRecSignal(GSN_DICTSTARTREQ, &Dbdict::execDICTSTARTREQ); + addRecSignal(GSN_READ_NODESCONF, &Dbdict::execREAD_NODESCONF); + addRecSignal(GSN_FSOPENCONF, &Dbdict::execFSOPENCONF); + addRecSignal(GSN_FSOPENREF, &Dbdict::execFSOPENREF); + addRecSignal(GSN_FSCLOSECONF, &Dbdict::execFSCLOSECONF); + addRecSignal(GSN_FSCLOSEREF, &Dbdict::execFSCLOSEREF); + addRecSignal(GSN_FSWRITECONF, &Dbdict::execFSWRITECONF); + addRecSignal(GSN_FSWRITEREF, &Dbdict::execFSWRITEREF); + addRecSignal(GSN_FSREADCONF, &Dbdict::execFSREADCONF); + addRecSignal(GSN_FSREADREF, &Dbdict::execFSREADREF); + addRecSignal(GSN_LQHFRAGCONF, &Dbdict::execLQHFRAGCONF); + addRecSignal(GSN_LQHADDATTCONF, &Dbdict::execLQHADDATTCONF); + addRecSignal(GSN_LQHADDATTREF, &Dbdict::execLQHADDATTREF); + addRecSignal(GSN_LQHFRAGREF, &Dbdict::execLQHFRAGREF); + addRecSignal(GSN_NDB_STTOR, &Dbdict::execNDB_STTOR); + addRecSignal(GSN_READ_CONFIG_REQ, &Dbdict::execREAD_CONFIG_REQ, true); + addRecSignal(GSN_STTOR, &Dbdict::execSTTOR); + addRecSignal(GSN_TC_SCHVERCONF, &Dbdict::execTC_SCHVERCONF); + addRecSignal(GSN_NODE_FAILREP, &Dbdict::execNODE_FAILREP); + addRecSignal(GSN_INCL_NODEREQ, &Dbdict::execINCL_NODEREQ); + addRecSignal(GSN_API_FAILREQ, &Dbdict::execAPI_FAILREQ); + + addRecSignal(GSN_WAIT_GCP_REF, &Dbdict::execWAIT_GCP_REF); + addRecSignal(GSN_WAIT_GCP_CONF, &Dbdict::execWAIT_GCP_CONF); + + addRecSignal(GSN_LIST_TABLES_REQ, &Dbdict::execLIST_TABLES_REQ); + + addRecSignal(GSN_DROP_TABLE_REQ, &Dbdict::execDROP_TABLE_REQ); + + addRecSignal(GSN_PREP_DROP_TAB_REQ, &Dbdict::execPREP_DROP_TAB_REQ); + addRecSignal(GSN_PREP_DROP_TAB_REF, &Dbdict::execPREP_DROP_TAB_REF); + addRecSignal(GSN_PREP_DROP_TAB_CONF, &Dbdict::execPREP_DROP_TAB_CONF); + + addRecSignal(GSN_DROP_TAB_REQ, &Dbdict::execDROP_TAB_REQ); + addRecSignal(GSN_DROP_TAB_REF, &Dbdict::execDROP_TAB_REF); + addRecSignal(GSN_DROP_TAB_CONF, &Dbdict::execDROP_TAB_CONF); +}//Dbdict::Dbdict() + +Dbdict::~Dbdict() +{ +}//Dbdict::~Dbdict() + +BLOCK_FUNCTIONS(Dbdict) + +void Dbdict::initCommonData() +{ +/* ---------------------------------------------------------------- */ +// Initialise all common variables. +/* ---------------------------------------------------------------- */ + initRetrieveRecord(0, 0, 0); + initSchemaRecord(); + initRestartRecord(); + initSendSchemaRecord(); + initReadTableRecord(); + initWriteTableRecord(); + initReadSchemaRecord(); + initWriteSchemaRecord(); + + c_masterNodeId = ZNIL; + c_numberNode = 0; + c_noNodesFailed = 0; + c_failureNr = 0; + c_blockState = BS_IDLE; + c_packTable.m_state = PackTable::PTS_IDLE; + c_startPhase = 0; + c_restartType = 255; //Ensure not used restartType + c_tabinfoReceived = 0; + c_initialStart = false; + c_systemRestart = false; + c_initialNodeRestart = false; + c_nodeRestart = false; +}//Dbdict::initCommonData() + +void Dbdict::initRecords() +{ + initNodeRecords(); + initPageRecords(); + initTableRecords(); + initTriggerRecords(); +}//Dbdict::initRecords() + +void Dbdict::initSendSchemaRecord() +{ + c_sendSchemaRecord.noOfWords = (Uint32)-1; + c_sendSchemaRecord.pageId = RNIL; + c_sendSchemaRecord.noOfWordsCurrentlySent = 0; + c_sendSchemaRecord.noOfSignalsSentSinceDelay = 0; + c_sendSchemaRecord.inUse = false; + //c_sendSchemaRecord.sendSchemaState = SendSchemaRecord::IDLE; +}//initSendSchemaRecord() + +void Dbdict::initReadTableRecord() +{ + c_readTableRecord.noOfPages = (Uint32)-1; + c_readTableRecord.pageId = RNIL; + c_readTableRecord.tableId = ZNIL; + c_readTableRecord.inUse = false; +}//initReadTableRecord() + +void Dbdict::initWriteTableRecord() +{ + c_writeTableRecord.noOfPages = (Uint32)-1; + c_writeTableRecord.pageId = RNIL; + c_writeTableRecord.noOfTableFilesHandled = 3; + c_writeTableRecord.tableId = ZNIL; + c_writeTableRecord.tableWriteState = WriteTableRecord::IDLE; +}//initWriteTableRecord() + +void Dbdict::initReadSchemaRecord() +{ + c_readSchemaRecord.pageId = RNIL; + c_readSchemaRecord.schemaReadState = ReadSchemaRecord::IDLE; +}//initReadSchemaRecord() + +void Dbdict::initWriteSchemaRecord() +{ + c_writeSchemaRecord.inUse = false; + c_writeSchemaRecord.pageId = RNIL; + c_writeSchemaRecord.noOfSchemaFilesHandled = 3; +}//initWriteSchemaRecord() + +void Dbdict::initRetrieveRecord(Signal* signal, Uint32 i, Uint32 returnCode) +{ + c_retrieveRecord.busyState = false; + c_retrieveRecord.blockRef = 0; + c_retrieveRecord.m_senderData = RNIL; + c_retrieveRecord.tableId = RNIL; + c_retrieveRecord.currentSent = 0; + c_retrieveRecord.retrievedNoOfPages = 0; + c_retrieveRecord.retrievedNoOfWords = 0; + c_retrieveRecord.m_useLongSig = false; +}//initRetrieveRecord() + +void Dbdict::initSchemaRecord() +{ + c_schemaRecord.schemaPage = RNIL; +}//Dbdict::initSchemaRecord() + +void Dbdict::initRestartRecord() +{ + c_restartRecord.gciToRestart = 0; + c_restartRecord.activeTable = ZNIL; +}//Dbdict::initRestartRecord() + +void Dbdict::initNodeRecords() +{ + jam(); + for (unsigned i = 1; i < MAX_NODES; i++) { + NodeRecordPtr nodePtr; + c_nodes.getPtr(nodePtr, i); + nodePtr.p->hotSpare = false; + nodePtr.p->nodeState = NodeRecord::API_NODE; + }//for +}//Dbdict::initNodeRecords() + +void Dbdict::initPageRecords() +{ + c_schemaRecord.schemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION; + c_schemaRecord.oldSchemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION + 1; + c_retrieveRecord.retrievePage = ZMAX_PAGES_OF_TABLE_DEFINITION + 2; + ndbrequire(ZNUMBER_OF_PAGES >= (2 * ZMAX_PAGES_OF_TABLE_DEFINITION + 2)); +}//Dbdict::initPageRecords() + +void Dbdict::initTableRecords() +{ + TableRecordPtr tablePtr; + while (1) { + jam(); + refresh_watch_dog(); + c_tableRecordPool.seize(tablePtr); + if (tablePtr.i == RNIL) { + jam(); + break; + }//if + initialiseTableRecord(tablePtr); + }//while +}//Dbdict::initTableRecords() + +void Dbdict::initialiseTableRecord(TableRecordPtr tablePtr) +{ + tablePtr.p->activePage = RNIL; + tablePtr.p->filePtr[0] = RNIL; + tablePtr.p->filePtr[1] = RNIL; + tablePtr.p->firstAttribute = RNIL; + tablePtr.p->firstPage = RNIL; + tablePtr.p->lastAttribute = RNIL; + tablePtr.p->tableId = tablePtr.i; + tablePtr.p->tableVersion = (Uint32)-1; + tablePtr.p->tabState = TableRecord::NOT_DEFINED; + tablePtr.p->tabReturnState = TableRecord::TRS_IDLE; + tablePtr.p->myConnect = RNIL; + tablePtr.p->fragmentType = DictTabInfo::AllNodesSmallTable; + memset(tablePtr.p->tableName, 0, sizeof(tablePtr.p->tableName)); + tablePtr.p->gciTableCreated = 0; + tablePtr.p->noOfAttributes = ZNIL; + tablePtr.p->noOfNullAttr = 0; + tablePtr.p->frmLen = 0; + memset(tablePtr.p->frmData, 0, sizeof(tablePtr.p->frmData)); + /* + tablePtr.p->lh3PageIndexBits = 0; + tablePtr.p->lh3DistrBits = 0; + tablePtr.p->lh3PageBits = 6; + */ + tablePtr.p->kValue = 6; + tablePtr.p->localKeyLen = 1; + tablePtr.p->maxLoadFactor = 80; + tablePtr.p->minLoadFactor = 70; + tablePtr.p->noOfPrimkey = 1; + tablePtr.p->tupKeyLength = 1; + tablePtr.p->storedTable = true; + tablePtr.p->tableType = DictTabInfo::UserTable; + tablePtr.p->primaryTableId = RNIL; + // volatile elements + tablePtr.p->indexState = TableRecord::IS_UNDEFINED; + tablePtr.p->insertTriggerId = RNIL; + tablePtr.p->updateTriggerId = RNIL; + tablePtr.p->deleteTriggerId = RNIL; + tablePtr.p->customTriggerId = RNIL; + tablePtr.p->buildTriggerId = RNIL; + tablePtr.p->indexLocal = 0; +}//Dbdict::initialiseTableRecord() + +void Dbdict::initTriggerRecords() +{ + TriggerRecordPtr triggerPtr; + while (1) { + jam(); + refresh_watch_dog(); + c_triggerRecordPool.seize(triggerPtr); + if (triggerPtr.i == RNIL) { + jam(); + break; + }//if + initialiseTriggerRecord(triggerPtr); + }//while +} + +void Dbdict::initialiseTriggerRecord(TriggerRecordPtr triggerPtr) +{ + triggerPtr.p->triggerState = TriggerRecord::TS_NOT_DEFINED; + triggerPtr.p->triggerLocal = 0; + memset(triggerPtr.p->triggerName, 0, sizeof(triggerPtr.p->triggerName)); + triggerPtr.p->triggerId = RNIL; + triggerPtr.p->tableId = RNIL; + triggerPtr.p->triggerType = (TriggerType::Value)~0; + triggerPtr.p->triggerActionTime = (TriggerActionTime::Value)~0; + triggerPtr.p->triggerEvent = (TriggerEvent::Value)~0; + triggerPtr.p->monitorReplicas = false; + triggerPtr.p->monitorAllAttributes = false; + triggerPtr.p->attributeMask.clear(); + triggerPtr.p->indexId = RNIL; +} + +Uint32 Dbdict::getFsConnRecord() +{ + FsConnectRecordPtr fsPtr; + c_fsConnectRecordPool.seize(fsPtr); + ndbrequire(fsPtr.i != RNIL); + fsPtr.p->filePtr = (Uint32)-1; + fsPtr.p->ownerPtr = RNIL; + fsPtr.p->fsState = FsConnectRecord::IDLE; + return fsPtr.i; +}//Dbdict::getFsConnRecord() + +Uint32 Dbdict::getFreeTableRecord(Uint32 primaryTableId) +{ + Uint32 minId = (primaryTableId == RNIL ? 0 : primaryTableId + 1); + TableRecordPtr tablePtr; + TableRecordPtr firstTablePtr; + bool firstFound = false; + Uint32 tabSize = c_tableRecordPool.getSize(); + for (tablePtr.i = minId; tablePtr.i < tabSize ; tablePtr.i++) { + jam(); + c_tableRecordPool.getPtr(tablePtr); + if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) { + jam(); + initialiseTableRecord(tablePtr); + tablePtr.p->tabState = TableRecord::DEFINING; + firstFound = true; + firstTablePtr.i = tablePtr.i; + firstTablePtr.p = tablePtr.p; + break; + }//if + }//for + if (!firstFound) { + jam(); + return RNIL; + }//if +#ifdef HAVE_TABLE_REORG + bool secondFound = false; + for (tablePtr.i = firstTablePtr.i + 1; tablePtr.i < tabSize ; tablePtr.i++) { + jam(); + c_tableRecordPool.getPtr(tablePtr); + if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) { + jam(); + initialiseTableRecord(tablePtr); + tablePtr.p->tabState = TableRecord::REORG_TABLE_PREPARED; + tablePtr.p->secondTable = firstTablePtr.i; + firstTablePtr.p->secondTable = tablePtr.i; + secondFound = true; + break; + }//if + }//for + if (!secondFound) { + jam(); + firstTablePtr.p->tabState = TableRecord::NOT_DEFINED; + return RNIL; + }//if +#endif + return firstTablePtr.i; +}//Dbdict::getFreeTableRecord() + +Uint32 Dbdict::getFreeTriggerRecord() +{ + const Uint32 size = c_triggerRecordPool.getSize(); + TriggerRecordPtr triggerPtr; + for (triggerPtr.i = 0; triggerPtr.i < size; triggerPtr.i++) { + jam(); + c_triggerRecordPool.getPtr(triggerPtr); + if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED) { + jam(); + initialiseTriggerRecord(triggerPtr); + return triggerPtr.i; + } + } + return RNIL; +} + +bool +Dbdict::getNewAttributeRecord(TableRecordPtr tablePtr, + AttributeRecordPtr & attrPtr) +{ + c_attributeRecordPool.seize(attrPtr); + if(attrPtr.i == RNIL){ + return false; + } + + memset(attrPtr.p->attributeName, 0, sizeof(attrPtr.p->attributeName)); + attrPtr.p->attributeDescriptor = 0x00012255; //Default value + attrPtr.p->attributeId = ZNIL; + attrPtr.p->nextAttrInTable = RNIL; + attrPtr.p->tupleKey = 0; + memset(attrPtr.p->defaultValue, 0, sizeof(attrPtr.p->defaultValue)); + + /* ---------------------------------------------------------------- */ + // A free attribute record has been acquired. We will now link it + // to the table record. + /* ---------------------------------------------------------------- */ + if (tablePtr.p->lastAttribute == RNIL) { + jam(); + tablePtr.p->firstAttribute = attrPtr.i; + } else { + jam(); + AttributeRecordPtr lastAttrPtr; + c_attributeRecordPool.getPtr(lastAttrPtr, tablePtr.p->lastAttribute); + lastAttrPtr.p->nextAttrInTable = attrPtr.i; + }//if + tablePtr.p->lastAttribute = attrPtr.i; + return true; +}//Dbdict::getNewAttributeRecord() + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: START/RESTART HANDLING ------------------------ */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code that is common for all */ +/* start/restart types. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// This is sent as the first signal during start/restart. +/* ---------------------------------------------------------------- */ +void Dbdict::execSTTOR(Signal* signal) +{ + jamEntry(); + c_startPhase = signal->theData[1]; + switch (c_startPhase) { + case 1: + break; + case 3: + c_restartType = signal->theData[7]; /* valid if 3 */ + ndbrequire(c_restartType == NodeState::ST_INITIAL_START || + c_restartType == NodeState::ST_SYSTEM_RESTART || + c_restartType == NodeState::ST_INITIAL_NODE_RESTART || + c_restartType == NodeState::ST_NODE_RESTART); + break; + } + sendSTTORRY(signal); +}//execSTTOR() + +void Dbdict::sendSTTORRY(Signal* signal) +{ + signal->theData[0] = 0; /* garbage SIGNAL KEY */ + signal->theData[1] = 0; /* garbage SIGNAL VERSION NUMBER */ + signal->theData[2] = 0; /* garbage */ + signal->theData[3] = 1; /* first wanted start phase */ + signal->theData[4] = 3; /* get type of start */ + signal->theData[5] = ZNOMOREPHASES; + sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 6, JBB); +} + +/* ---------------------------------------------------------------- */ +// We receive information about sizes of records. +/* ---------------------------------------------------------------- */ +void Dbdict::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); + + Uint32 attributesize, tablerecSize; + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_ATTRIBUTE,&attributesize)); + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_TABLE, &tablerecSize)); + + c_attributeRecordPool.setSize(attributesize); + c_attributeRecordHash.setSize(64); + c_fsConnectRecordPool.setSize(ZFS_CONNECT_SIZE); + c_nodes.setSize(MAX_NODES); + c_pageRecordArray.setSize(ZNUMBER_OF_PAGES); + c_tableRecordPool.setSize(tablerecSize); + c_tableRecordHash.setSize(tablerecSize); + c_triggerRecordPool.setSize(c_maxNoOfTriggers); + c_triggerRecordHash.setSize(c_maxNoOfTriggers); + c_opRecordPool.setSize(256); // XXX need config params + c_opCreateTable.setSize(8); + c_opDropTable.setSize(8); + c_opCreateIndex.setSize(8); + c_opCreateEvent.setSize(8); + c_opSubEvent.setSize(8); + c_opDropEvent.setSize(8); + c_opSignalUtil.setSize(8); + c_opDropIndex.setSize(8); + c_opAlterIndex.setSize(8); + c_opBuildIndex.setSize(8); + c_opCreateTrigger.setSize(8); + c_opDropTrigger.setSize(8); + c_opAlterTrigger.setSize(8); + + // Initialize BAT for interface to file system + PageRecordPtr pageRecPtr; + c_pageRecordArray.getPtr(pageRecPtr, 0); + NewVARIABLE* bat = allocateBat(2); + bat[1].WA = &pageRecPtr.p->word[0]; + bat[1].nrr = ZNUMBER_OF_PAGES; + bat[1].ClusterSize = ZSIZE_OF_PAGES_IN_WORDS * 4; + bat[1].bits.q = ZLOG_SIZE_OF_PAGES_IN_WORDS; // 2**13 = 8192 elements + bat[1].bits.v = 5; // 32 bits per element + + initCommonData(); + initRecords(); + + ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + sendSignal(ref, GSN_READ_CONFIG_CONF, signal, + ReadConfigConf::SignalLength, JBB); +}//execSIZEALT_REP() + +/* ---------------------------------------------------------------- */ +// Start phase signals sent by CNTR. We reply with NDB_STTORRY when +// we completed this phase. +/* ---------------------------------------------------------------- */ +void Dbdict::execNDB_STTOR(Signal* signal) +{ + jamEntry(); + c_startPhase = signal->theData[2]; + const Uint32 restartType = signal->theData[3]; + if (restartType == NodeState::ST_INITIAL_START) { + jam(); + c_initialStart = true; + } else if (restartType == NodeState::ST_SYSTEM_RESTART) { + jam(); + c_systemRestart = true; + } else if (restartType == NodeState::ST_INITIAL_NODE_RESTART) { + jam(); + c_initialNodeRestart = true; + } else if (restartType == NodeState::ST_NODE_RESTART) { + jam(); + c_nodeRestart = true; + } else { + ndbrequire(false); + }//if + switch (c_startPhase) { + case 1: + jam(); + initSchemaFile(signal); + break; + case 3: + jam(); + signal->theData[0] = reference(); + sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB); + break; + case 6: + jam(); + c_initialStart = false; + c_systemRestart = false; + c_initialNodeRestart = false; + c_nodeRestart = false; + sendNDB_STTORRY(signal); + break; + case 7: + // uses c_restartType + if(restartType == NodeState::ST_SYSTEM_RESTART && + c_masterNodeId == getOwnNodeId()){ + rebuildIndexes(signal, 0); + return; + } + sendNDB_STTORRY(signal); + break; + default: + jam(); + sendNDB_STTORRY(signal); + break; + }//switch +}//execNDB_STTOR() + +void Dbdict::sendNDB_STTORRY(Signal* signal) +{ + signal->theData[0] = reference(); + sendSignal(NDBCNTR_REF, GSN_NDB_STTORRY, signal, 1, JBB); + return; +}//sendNDB_STTORRY() + +/* ---------------------------------------------------------------- */ +// We receive the information about which nodes that are up and down. +/* ---------------------------------------------------------------- */ +void Dbdict::execREAD_NODESCONF(Signal* signal) +{ + jamEntry(); + + ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0]; + c_numberNode = readNodes->noOfNodes; + c_masterNodeId = readNodes->masterNodeId; + + c_noNodesFailed = 0; + c_aliveNodes.clear(); + for (unsigned i = 1; i < MAX_NDB_NODES; i++) { + jam(); + NodeRecordPtr nodePtr; + c_nodes.getPtr(nodePtr, i); + + if (NodeBitmask::get(readNodes->allNodes, i)) { + jam(); + nodePtr.p->nodeState = NodeRecord::NDB_NODE_ALIVE; + if (NodeBitmask::get(readNodes->inactiveNodes, i)) { + jam(); + /**------------------------------------------------------------------- + * + * THIS NODE IS DEFINED IN THE CLUSTER BUT IS NOT ALIVE CURRENTLY. + * WE ADD THE NODE TO THE SET OF FAILED NODES AND ALSO SET THE + * BLOCKSTATE TO BUSY TO AVOID ADDING TABLES WHILE NOT ALL NODES ARE + * ALIVE. + *------------------------------------------------------------------*/ + nodePtr.p->nodeState = NodeRecord::NDB_NODE_DEAD; + c_noNodesFailed++; + } else { + c_aliveNodes.set(i); + } + }//if + }//for + sendNDB_STTORRY(signal); +}//execREAD_NODESCONF() + +/* ---------------------------------------------------------------- */ +// HOT_SPAREREP informs DBDICT about which nodes that have become +// hot spare nodes. +/* ---------------------------------------------------------------- */ +void Dbdict::execHOT_SPAREREP(Signal* signal) +{ + Uint32 hotSpareNodes = 0; + jamEntry(); + HotSpareRep * const hotSpare = (HotSpareRep*)&signal->theData[0]; + for (unsigned i = 1; i < MAX_NDB_NODES; i++) { + if (NodeBitmask::get(hotSpare->theHotSpareNodes, i)) { + NodeRecordPtr nodePtr; + c_nodes.getPtr(nodePtr, i); + nodePtr.p->hotSpare = true; + hotSpareNodes++; + }//if + }//for + ndbrequire(hotSpareNodes == hotSpare->noHotSpareNodes); + c_noHotSpareNodes = hotSpareNodes; + return; +}//execHOT_SPAREREP() + +void Dbdict::initSchemaFile(Signal* signal) +{ + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + SchemaFile * schemaFile = (SchemaFile *)pagePtr.p; + initSchemaFile(schemaFile, 4 * ZSIZE_OF_PAGES_IN_WORDS); + + if (c_initialStart || c_initialNodeRestart) { + jam(); + ndbrequire(c_writeSchemaRecord.inUse == false); + c_writeSchemaRecord.inUse = true; + c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage; + + c_writeSchemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::initSchemaFile_conf); + + startWriteSchemaFile(signal); + } else if (c_systemRestart || c_nodeRestart) { + jam(); + ndbrequire(c_readSchemaRecord.schemaReadState == ReadSchemaRecord::IDLE); + c_readSchemaRecord.pageId = c_schemaRecord.oldSchemaPage; + c_readSchemaRecord.schemaReadState = ReadSchemaRecord::INITIAL_READ; + startReadSchemaFile(signal); + } else { + ndbrequire(false); + }//if +}//Dbdict::initSchemaFile() + +void +Dbdict::initSchemaFile_conf(Signal* signal, Uint32 callbackData, Uint32 rv){ + jam(); + sendNDB_STTORRY(signal); +} + +void +Dbdict::activateIndexes(Signal* signal, Uint32 i) +{ + AlterIndxReq* req = (AlterIndxReq*)signal->getDataPtrSend(); + TableRecordPtr tablePtr; + for (; i < c_tableRecordPool.getSize(); i++) { + tablePtr.i = i; + c_tableRecordPool.getPtr(tablePtr); + if (tablePtr.p->tabState != TableRecord::DEFINED) + continue; + if (! tablePtr.p->isIndex()) + continue; + jam(); + req->setUserRef(reference()); + req->setConnectionPtr(i); + req->setTableId(tablePtr.p->primaryTableId); + req->setIndexId(tablePtr.i); + req->setIndexVersion(tablePtr.p->tableVersion); + req->setOnline(true); + if (c_restartType == NodeState::ST_SYSTEM_RESTART) { + if (c_masterNodeId != getOwnNodeId()) + continue; + // from file index state is not defined currently + req->setRequestType(AlterIndxReq::RT_SYSTEMRESTART); + req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD); + } + else if ( + c_restartType == NodeState::ST_NODE_RESTART || + c_restartType == NodeState::ST_INITIAL_NODE_RESTART) { + // from master index must be online + if (tablePtr.p->indexState != TableRecord::IS_ONLINE) + continue; + req->setRequestType(AlterIndxReq::RT_NODERESTART); + // activate locally, rebuild not needed + req->addRequestFlag((Uint32)RequestFlag::RF_LOCAL); + req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD); + } else { + ndbrequire(false); + } + sendSignal(reference(), GSN_ALTER_INDX_REQ, + signal, AlterIndxReq::SignalLength, JBB); + return; + } + signal->theData[0] = reference(); + sendSignal(c_restartRecord.returnBlockRef, GSN_DICTSTARTCONF, + signal, 1, JBB); +} + +void +Dbdict::rebuildIndexes(Signal* signal, Uint32 i){ + BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend(); + + TableRecordPtr indexPtr; + for (; i < c_tableRecordPool.getSize(); i++) { + indexPtr.i = i; + c_tableRecordPool.getPtr(indexPtr); + if (indexPtr.p->tabState != TableRecord::DEFINED) + continue; + if (! indexPtr.p->isIndex()) + continue; + + jam(); + + req->setUserRef(reference()); + req->setConnectionPtr(i); + req->setRequestType(BuildIndxReq::RT_SYSTEMRESTART); + req->setBuildId(0); // not used + req->setBuildKey(0); // not used + req->setIndexType(indexPtr.p->tableType); + req->setIndexId(indexPtr.i); + req->setTableId(indexPtr.p->primaryTableId); + req->setParallelism(16); + + // from file index state is not defined currently + if (indexPtr.p->storedTable) { + // rebuild not needed + req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD); + } + + // send + sendSignal(reference(), GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength, JBB); + return; + } + sendNDB_STTORRY(signal); +} + + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: SYSTEM RESTART MODULE ------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains code specific for system restart */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// DIH asks DICT to read in table data from disk during system +// restart. DIH also asks DICT to send information about which +// tables that should be started as part of this system restart. +// DICT will also activate the tables in TC as part of this process. +/* ---------------------------------------------------------------- */ +void Dbdict::execDICTSTARTREQ(Signal* signal) +{ + jamEntry(); + c_restartRecord.gciToRestart = signal->theData[0]; + c_restartRecord.returnBlockRef = signal->theData[1]; + if (c_nodeRestart || c_initialNodeRestart) { + jam(); + + CRASH_INSERTION(6000); + + BlockReference dictRef = calcDictBlockRef(c_masterNodeId); + signal->theData[0] = getOwnNodeId(); + sendSignal(dictRef, GSN_GET_SCHEMA_INFOREQ, signal, 1, JBB); + return; + } + ndbrequire(c_systemRestart); + ndbrequire(c_masterNodeId == getOwnNodeId()); + + c_schemaRecord.m_callback.m_callbackData = 0; + c_schemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::masterRestart_checkSchemaStatusComplete); + + c_restartRecord.activeTable = 0; + c_schemaRecord.schemaPage = c_schemaRecord.oldSchemaPage; + checkSchemaStatus(signal); +}//execDICTSTARTREQ() + +void +Dbdict::masterRestart_checkSchemaStatusComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + + c_schemaRecord.schemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION; + + LinearSectionPtr ptr[3]; + + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.oldSchemaPage); + + ptr[0].p = &pagePtr.p->word[0]; + ptr[0].sz = ZSIZE_OF_PAGES_IN_WORDS; + + c_sendSchemaRecord.m_SCHEMAINFO_Counter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + + rg.m_nodes.clear(getOwnNodeId()); + Callback c = { 0, 0 }; + sendFragmentedSignal(rg, + GSN_SCHEMA_INFO, + signal, + 1, //SchemaInfo::SignalLength, + JBB, + ptr, + 1, + c); + + PageRecordPtr newPagePtr; + c_pageRecordArray.getPtr(newPagePtr, c_schemaRecord.schemaPage); + memcpy(&newPagePtr.p->word[0], &pagePtr.p->word[0], + 4 * ZSIZE_OF_PAGES_IN_WORDS); + + signal->theData[0] = getOwnNodeId(); + sendSignal(reference(), GSN_SCHEMA_INFOCONF, signal, 1, JBB); +} + +void +Dbdict::execGET_SCHEMA_INFOREQ(Signal* signal){ + + const Uint32 ref = signal->getSendersBlockRef(); + //const Uint32 senderData = signal->theData[0]; + + ndbrequire(c_sendSchemaRecord.inUse == false); + c_sendSchemaRecord.inUse = true; + + LinearSectionPtr ptr[3]; + + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + ptr[0].p = &pagePtr.p->word[0]; + ptr[0].sz = ZSIZE_OF_PAGES_IN_WORDS; + + Callback c = { safe_cast(&Dbdict::sendSchemaComplete), 0 }; + sendFragmentedSignal(ref, + GSN_SCHEMA_INFO, + signal, + 1, //GetSchemaInfoConf::SignalLength, + JBB, + ptr, + 1, + c); +}//Dbdict::execGET_SCHEMA_INFOREQ() + +void +Dbdict::sendSchemaComplete(Signal * signal, + Uint32 callbackData, + Uint32 returnCode){ + ndbrequire(c_sendSchemaRecord.inUse == true); + c_sendSchemaRecord.inUse = false; + +} + + +/* ---------------------------------------------------------------- */ +// We receive the schema info from master as part of all restarts +// except the initial start where no tables exists. +/* ---------------------------------------------------------------- */ +void Dbdict::execSCHEMA_INFO(Signal* signal) +{ + jamEntry(); + if(!assembleFragments(signal)){ + jam(); + return; + } + + if(getNodeState().getNodeRestartInProgress()){ + CRASH_INSERTION(6001); + } + + SegmentedSectionPtr schemaDataPtr; + signal->getSection(schemaDataPtr, 0); + + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + copy(&pagePtr.p->word[0], schemaDataPtr); + releaseSections(signal); + + validateChecksum((SchemaFile*)pagePtr.p); + + ndbrequire(signal->getSendersBlockRef() != reference()); + + /* ---------------------------------------------------------------- */ + // Synchronise our view on data with other nodes in the cluster. + // This is an important part of restart handling where we will handle + // cases where the table have been added but only partially, where + // tables have been deleted but not completed the deletion yet and + // other scenarios needing synchronisation. + /* ---------------------------------------------------------------- */ + c_schemaRecord.m_callback.m_callbackData = 0; + c_schemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::restart_checkSchemaStatusComplete); + c_restartRecord.activeTable = 0; + checkSchemaStatus(signal); +}//execSCHEMA_INFO() + +void +Dbdict::restart_checkSchemaStatusComplete(Signal * signal, + Uint32 callbackData, + Uint32 returnCode){ + + ndbrequire(c_writeSchemaRecord.inUse == false); + c_writeSchemaRecord.inUse = true; + c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage; + c_writeSchemaRecord.m_callback.m_callbackData = 0; + c_writeSchemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::restart_writeSchemaConf); + + startWriteSchemaFile(signal); +} + +void +Dbdict::restart_writeSchemaConf(Signal * signal, + Uint32 callbackData, + Uint32 returnCode){ + + if(c_systemRestart){ + jam(); + signal->theData[0] = getOwnNodeId(); + sendSignal(calcDictBlockRef(c_masterNodeId), GSN_SCHEMA_INFOCONF, + signal, 1, JBB); + return; + } + + ndbrequire(c_nodeRestart || c_initialNodeRestart); + c_blockState = BS_IDLE; + activateIndexes(signal, 0); + return; +} + +void Dbdict::execSCHEMA_INFOCONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + +/* ---------------------------------------------------------------- */ +// This signal is received in the master as part of system restart +// from all nodes (including the master) after they have synchronised +// their data with the master node's schema information. +/* ---------------------------------------------------------------- */ + const Uint32 nodeId = signal->theData[0]; + c_sendSchemaRecord.m_SCHEMAINFO_Counter.clearWaitingFor(nodeId); + + if (!c_sendSchemaRecord.m_SCHEMAINFO_Counter.done()){ + jam(); + return; + }//if + activateIndexes(signal, 0); +}//execSCHEMA_INFOCONF() + +void Dbdict::checkSchemaStatus(Signal* signal) +{ + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + PageRecordPtr oldPagePtr; + c_pageRecordArray.getPtr(oldPagePtr, c_schemaRecord.oldSchemaPage); + + for (; c_restartRecord.activeTable < MAX_TABLES; + c_restartRecord.activeTable++) { + jam(); + + Uint32 tableId = c_restartRecord.activeTable; + SchemaFile::TableEntry *newEntry = getTableEntry(pagePtr.p, tableId); + SchemaFile::TableEntry *oldEntry = getTableEntry(oldPagePtr.p, tableId, + true); + SchemaFile::TableState schemaState = + (SchemaFile::TableState)newEntry->m_tableState; + SchemaFile::TableState oldSchemaState = + (SchemaFile::TableState)oldEntry->m_tableState; + + if (c_restartRecord.activeTable >= c_tableRecordPool.getSize()) { + jam(); + ndbrequire(schemaState == SchemaFile::INIT); + ndbrequire(oldSchemaState == SchemaFile::INIT); + continue; + }//if + + switch(schemaState){ + case SchemaFile::INIT:{ + jam(); + bool ok = false; + switch(oldSchemaState) { + case SchemaFile::INIT: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + ok = true; + jam(); + break; + + case SchemaFile::ADD_STARTED: + jam(); + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + ok = true; + jam(); + newEntry->m_tableState = SchemaFile::INIT; + restartDropTab(signal, tableId); + return; + }//switch + ndbrequire(ok); + break; + } + case SchemaFile::ADD_STARTED:{ + jam(); + bool ok = false; + switch(oldSchemaState) { + case SchemaFile::INIT: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + ok = true; + break; + case SchemaFile::ADD_STARTED: + jam(); + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + ok = true; + //------------------------------------------------------------------ + // Add Table was started but not completed. Will be dropped in all + // nodes. Update schema information (restore table version). + //------------------------------------------------------------------ + newEntry->m_tableState = SchemaFile::INIT; + restartDropTab(signal, tableId); + return; + } + ndbrequire(ok); + break; + } + case SchemaFile::TABLE_ADD_COMMITTED:{ + jam(); + bool ok = false; + switch(oldSchemaState) { + case SchemaFile::INIT: + jam(); + case SchemaFile::ADD_STARTED: + jam(); + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + ok = true; + //------------------------------------------------------------------ + // Table was added in the master node but not in our node. We can + // retrieve the table definition from the master. + //------------------------------------------------------------------ + restartCreateTab(signal, tableId, oldEntry, false); + return; + break; + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + ok = true; + //------------------------------------------------------------------ + // Table was added in both our node and the master node. We can + // retrieve the table definition from our own disk. + //------------------------------------------------------------------ + if(* newEntry == * oldEntry){ + jam(); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + tablePtr.p->tableVersion = oldEntry->m_tableVersion; + tablePtr.p->tableType = (DictTabInfo::TableType)oldEntry->m_tableType; + + // On NR get index from master because index state is not on file + const bool file = c_systemRestart || tablePtr.p->isTable(); + restartCreateTab(signal, tableId, oldEntry, file); + + return; + } else { + //------------------------------------------------------------------ + // Must be a new version of the table if anything differs. Both table + // version and global checkpoint must be different. + // This should not happen for the master node. This can happen after + // drop table followed by add table or after change table. + // Not supported in this version. + //------------------------------------------------------------------ + ndbrequire(c_masterNodeId != getOwnNodeId()); + ndbrequire(newEntry->m_tableVersion != oldEntry->m_tableVersion); + jam(); + + restartCreateTab(signal, tableId, oldEntry, false); + return; + }//if + } + ndbrequire(ok); + break; + } + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED:{ + jam(); + bool ok = false; + switch(oldSchemaState){ + case SchemaFile::INIT: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + ok = true; + break; + case SchemaFile::ADD_STARTED: + jam(); + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + newEntry->m_tableState = SchemaFile::INIT; + restartDropTab(signal, tableId); + return; + } + ndbrequire(ok); + break; + } + case SchemaFile::ALTER_TABLE_COMMITTED: { + jam(); + bool ok = false; + switch(oldSchemaState) { + case SchemaFile::INIT: + jam(); + case SchemaFile::ADD_STARTED: + jam(); + case SchemaFile::DROP_TABLE_STARTED: + jam(); + case SchemaFile::DROP_TABLE_COMMITTED: + jam(); + case SchemaFile::TABLE_ADD_COMMITTED: + jam(); + ok = true; + //------------------------------------------------------------------ + // Table was altered in the master node but not in our node. We can + // retrieve the altered table definition from the master. + //------------------------------------------------------------------ + restartCreateTab(signal, tableId, oldEntry, false); + return; + break; + case SchemaFile::ALTER_TABLE_COMMITTED: + jam(); + ok = true; + + //------------------------------------------------------------------ + // Table was altered in both our node and the master node. We can + // retrieve the table definition from our own disk. + //------------------------------------------------------------------ + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + tablePtr.p->tableVersion = oldEntry->m_tableVersion; + tablePtr.p->tableType = (DictTabInfo::TableType)oldEntry->m_tableType; + + // On NR get index from master because index state is not on file + const bool file = c_systemRestart || tablePtr.p->isTable(); + restartCreateTab(signal, tableId, oldEntry, file); + + return; + } + ndbrequire(ok); + break; + } + } + } + + execute(signal, c_schemaRecord.m_callback, 0); +}//checkSchemaStatus() + +void +Dbdict::restartCreateTab(Signal* signal, Uint32 tableId, + const SchemaFile::TableEntry * te, bool file){ + jam(); + + CreateTableRecordPtr createTabPtr; + c_opCreateTable.seize(createTabPtr); + ndbrequire(!createTabPtr.isNull()); + + createTabPtr.p->key = ++c_opRecordSequence; + c_opCreateTable.add(createTabPtr); + + createTabPtr.p->m_errorCode = 0; + createTabPtr.p->m_tablePtrI = tableId; + createTabPtr.p->m_coordinatorRef = reference(); + createTabPtr.p->m_senderRef = 0; + createTabPtr.p->m_senderData = RNIL; + createTabPtr.p->m_tabInfoPtrI = RNIL; + createTabPtr.p->m_dihAddFragPtr = RNIL; + + if(file && !ERROR_INSERTED(6002)){ + jam(); + + c_readTableRecord.noOfPages = te->m_noOfPages; + c_readTableRecord.pageId = 0; + c_readTableRecord.m_callback.m_callbackData = createTabPtr.p->key; + c_readTableRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::restartCreateTab_readTableConf); + + startReadTableFile(signal, tableId); + return; + } else { + + ndbrequire(c_masterNodeId != getOwnNodeId()); + + /** + * Get from master + */ + GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0]; + req->senderRef = reference(); + req->senderData = createTabPtr.p->key; + req->requestType = GetTabInfoReq::RequestById | + GetTabInfoReq::LongSignalConf; + req->tableId = tableId; + sendSignal(calcDictBlockRef(c_masterNodeId), GSN_GET_TABINFOREQ, signal, + GetTabInfoReq::SignalLength, JBB); + + if(ERROR_INSERTED(6002)){ + NdbSleep_MilliSleep(10); + CRASH_INSERTION(6002); + } + } +} + +void +Dbdict::restartCreateTab_readTableConf(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + PageRecordPtr pageRecPtr; + c_pageRecordArray.getPtr(pageRecPtr, c_readTableRecord.pageId); + + ParseDictTabInfoRecord parseRecord; + parseRecord.requestType = DictTabInfo::GetTabInfoConf; + parseRecord.errorCode = 0; + + Uint32 sz = c_readTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS; + SimplePropertiesLinearReader r(&pageRecPtr.p->word[0], sz); + handleTabInfoInit(r, &parseRecord); + ndbrequire(parseRecord.errorCode == 0); + + /* ---------------------------------------------------------------- */ + // We have read the table description from disk as part of system restart. + // We will also write it back again to ensure that both copies are ok. + /* ---------------------------------------------------------------- */ + ndbrequire(c_writeTableRecord.tableWriteState == WriteTableRecord::IDLE); + c_writeTableRecord.noOfPages = c_readTableRecord.noOfPages; + c_writeTableRecord.pageId = c_readTableRecord.pageId; + c_writeTableRecord.tableWriteState = WriteTableRecord::TWR_CALLBACK; + c_writeTableRecord.m_callback.m_callbackData = callbackData; + c_writeTableRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::restartCreateTab_writeTableConf); + startWriteTableFile(signal, c_readTableRecord.tableId); +} + +void +Dbdict::execGET_TABINFO_CONF(Signal* signal){ + jamEntry(); + + if(!assembleFragments(signal)){ + jam(); + return; + } + + GetTabInfoConf * const conf = (GetTabInfoConf*)signal->getDataPtr(); + + const Uint32 tableId = conf->tableId; + const Uint32 senderData = conf->senderData; + + SegmentedSectionPtr tabInfoPtr; + signal->getSection(tabInfoPtr, GetTabInfoConf::DICT_TAB_INFO); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, senderData)); + ndbrequire(!createTabPtr.isNull()); + ndbrequire(createTabPtr.p->m_tablePtrI == tableId); + + /** + * Put data into table record + */ + ParseDictTabInfoRecord parseRecord; + parseRecord.requestType = DictTabInfo::GetTabInfoConf; + parseRecord.errorCode = 0; + + SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool()); + handleTabInfoInit(r, &parseRecord); + ndbrequire(parseRecord.errorCode == 0); + + Callback callback; + callback.m_callbackData = createTabPtr.p->key; + callback.m_callbackFunction = + safe_cast(&Dbdict::restartCreateTab_writeTableConf); + + signal->header.m_noOfSections = 0; + writeTableFile(signal, createTabPtr.p->m_tablePtrI, tabInfoPtr, &callback); + signal->setSection(tabInfoPtr, 0); + releaseSections(signal); +} + +void +Dbdict::restartCreateTab_writeTableConf(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + Callback callback; + callback.m_callbackData = callbackData; + callback.m_callbackFunction = + safe_cast(&Dbdict::restartCreateTab_dihComplete); + + SegmentedSectionPtr fragDataPtr; + fragDataPtr.sz = 0; + fragDataPtr.setNull(); + createTab_dih(signal, createTabPtr, fragDataPtr, &callback); +} + +void +Dbdict::restartCreateTab_dihComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + //@todo check error + ndbrequire(createTabPtr.p->m_errorCode == 0); + + Callback callback; + callback.m_callbackData = callbackData; + callback.m_callbackFunction = + safe_cast(&Dbdict::restartCreateTab_activateComplete); + + alterTab_activate(signal, createTabPtr, &callback); +} + +void +Dbdict::restartCreateTab_activateComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + tabPtr.p->tabState = TableRecord::DEFINED; + + c_opCreateTable.release(createTabPtr); + + c_restartRecord.activeTable++; + checkSchemaStatus(signal); +} + +void +Dbdict::restartDropTab(Signal* signal, Uint32 tableId){ + + const Uint32 key = ++c_opRecordSequence; + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.seize(dropTabPtr)); + + dropTabPtr.p->key = key; + c_opDropTable.add(dropTabPtr); + + dropTabPtr.p->m_errorCode = 0; + dropTabPtr.p->m_request.tableId = tableId; + dropTabPtr.p->m_coordinatorRef = 0; + dropTabPtr.p->m_requestType = DropTabReq::RestartDropTab; + dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ; + + + dropTabPtr.p->m_participantData.m_block = 0; + dropTabPtr.p->m_participantData.m_callback.m_callbackData = key; + dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = + safe_cast(&Dbdict::restartDropTab_complete); + dropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::restartDropTab_complete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, callbackData)); + + //@todo check error + + c_opDropTable.release(dropTabPtr); + + c_restartRecord.activeTable++; + checkSchemaStatus(signal); +} + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: NODE FAILURE HANDLING ------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code that is used when nodes */ +/* (kernel/api) fails. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// We receive a report of an API that failed. +/* ---------------------------------------------------------------- */ +void Dbdict::execAPI_FAILREQ(Signal* signal) +{ + jamEntry(); + Uint32 failedApiNode = signal->theData[0]; + BlockReference retRef = signal->theData[1]; + +#if 0 + Uint32 userNode = refToNode(c_connRecord.userBlockRef); + if (userNode == failedApiNode) { + jam(); + c_connRecord.userBlockRef = (Uint32)-1; + }//if +#endif + + signal->theData[0] = failedApiNode; + signal->theData[1] = reference(); + sendSignal(retRef, GSN_API_FAILCONF, signal, 2, JBB); +}//execAPI_FAILREQ() + +/* ---------------------------------------------------------------- */ +// We receive a report of one or more node failures of kernel nodes. +/* ---------------------------------------------------------------- */ +void Dbdict::execNODE_FAILREP(Signal* signal) +{ + jamEntry(); + NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0]; + + c_failureNr = nodeFail->failNo; + const Uint32 numberOfFailedNodes = nodeFail->noOfNodes; + const bool masterFailed = (c_masterNodeId != nodeFail->masterNodeId); + c_masterNodeId = nodeFail->masterNodeId; + + c_noNodesFailed += numberOfFailedNodes; + Uint32 theFailedNodes[NodeBitmask::Size]; + memcpy(theFailedNodes, nodeFail->theNodes, sizeof(theFailedNodes)); + + c_counterMgr.execNODE_FAILREP(signal); + + bool ok = false; + switch(c_blockState){ + case BS_IDLE: + jam(); + ok = true; + if(c_opRecordPool.getSize() != c_opRecordPool.getNoOfFree()){ + jam(); + c_blockState = BS_NODE_FAILURE; + } + break; + case BS_CREATE_TAB: + jam(); + ok = true; + if(!masterFailed) + break; + // fall through + case BS_BUSY: + case BS_NODE_FAILURE: + jam(); + c_blockState = BS_NODE_FAILURE; + ok = true; + break; + } + ndbrequire(ok); + + for(unsigned i = 1; i < MAX_NDB_NODES; i++) { + jam(); + if(NodeBitmask::get(theFailedNodes, i)) { + jam(); + NodeRecordPtr nodePtr; + c_nodes.getPtr(nodePtr, i); + + nodePtr.p->nodeState = NodeRecord::NDB_NODE_DEAD; + NFCompleteRep * const nfCompRep = (NFCompleteRep *)&signal->theData[0]; + nfCompRep->blockNo = DBDICT; + nfCompRep->nodeId = getOwnNodeId(); + nfCompRep->failedNodeId = nodePtr.i; + sendSignal(DBDIH_REF, GSN_NF_COMPLETEREP, signal, + NFCompleteRep::SignalLength, JBB); + + c_aliveNodes.clear(i); + }//if + }//for + +}//execNODE_FAILREP() + + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: NODE START HANDLING --------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code that is used when kernel nodes */ +/* starts. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// Include a starting node in list of nodes to be part of adding +// and dropping tables. +/* ---------------------------------------------------------------- */ +void Dbdict::execINCL_NODEREQ(Signal* signal) +{ + jamEntry(); + NodeRecordPtr nodePtr; + BlockReference retRef = signal->theData[0]; + nodePtr.i = signal->theData[1]; + + ndbrequire(c_noNodesFailed > 0); + c_noNodesFailed--; + + c_nodes.getPtr(nodePtr); + ndbrequire(nodePtr.p->nodeState == NodeRecord::NDB_NODE_DEAD); + nodePtr.p->nodeState = NodeRecord::NDB_NODE_ALIVE; + signal->theData[0] = reference(); + sendSignal(retRef, GSN_INCL_NODECONF, signal, 1, JBB); + + c_aliveNodes.set(nodePtr.i); +}//execINCL_NODEREQ() + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: ADD TABLE HANDLING ---------------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code that is used when adding a table. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +/* ---------------------------------------------------------------- */ +// This signal receives information about a table from either: +// API, Ndbcntr or from other DICT. +/* ---------------------------------------------------------------- */ +void +Dbdict::execCREATE_TABLE_REQ(Signal* signal){ + jamEntry(); + if(!assembleFragments(signal)){ + return; + } + + CreateTableReq* const req = (CreateTableReq*)signal->getDataPtr(); + const Uint32 senderRef = req->senderRef; + const Uint32 senderData = req->senderData; + + ParseDictTabInfoRecord parseRecord; + do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + parseRecord.errorCode = CreateTableRef::NotMaster; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + parseRecord.errorCode = CreateTableRef::Busy; + break; + } + + CreateTableRecordPtr createTabPtr; + c_opCreateTable.seize(createTabPtr); + + if(createTabPtr.isNull()){ + jam(); + parseRecord.errorCode = CreateTableRef::Busy; + break; + } + + parseRecord.requestType = DictTabInfo::CreateTableFromAPI; + parseRecord.errorCode = 0; + + SegmentedSectionPtr ptr; + signal->getSection(ptr, CreateTableReq::DICT_TAB_INFO); + SimplePropertiesSectionReader r(ptr, getSectionSegmentPool()); + + handleTabInfoInit(r, &parseRecord); + releaseSections(signal); + + if(parseRecord.errorCode != 0){ + jam(); + c_opCreateTable.release(createTabPtr); + break; + } + + createTabPtr.p->key = ++c_opRecordSequence; + c_opCreateTable.add(createTabPtr); + createTabPtr.p->m_errorCode = 0; + createTabPtr.p->m_senderRef = senderRef; + createTabPtr.p->m_senderData = senderData; + createTabPtr.p->m_tablePtrI = parseRecord.tablePtr.i; + createTabPtr.p->m_coordinatorRef = reference(); + createTabPtr.p->m_fragmentsPtrI = RNIL; + createTabPtr.p->m_dihAddFragPtr = RNIL; + + Uint32 * theData = signal->getDataPtrSend(); + CreateFragmentationReq * const req = (CreateFragmentationReq*)theData; + req->senderRef = reference(); + req->senderData = createTabPtr.p->key; + req->fragmentationType = parseRecord.tablePtr.p->fragmentType; + req->noOfFragments = 0; + req->fragmentNode = 0; + req->primaryTableId = RNIL; + if (parseRecord.tablePtr.p->isOrderedIndex()) { + // ordered index has same fragmentation as the table + const Uint32 primaryTableId = parseRecord.tablePtr.p->primaryTableId; + TableRecordPtr primaryTablePtr; + c_tableRecordPool.getPtr(primaryTablePtr, primaryTableId); + // fragmentationType must be consistent + req->fragmentationType = primaryTablePtr.p->fragmentType; + req->primaryTableId = primaryTableId; + } + sendSignal(DBDIH_REF, GSN_CREATE_FRAGMENTATION_REQ, signal, + CreateFragmentationReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; + } while(0); + + /** + * Something went wrong + */ + releaseSections(signal); + + CreateTableRef * ref = (CreateTableRef*)signal->getDataPtrSend(); + ref->senderData = senderData; + ref->senderRef = reference(); + ref->masterNodeId = c_masterNodeId; + ref->errorCode = parseRecord.errorCode; + ref->errorLine = parseRecord.errorLine; + ref->errorKey = parseRecord.errorKey; + ref->status = parseRecord.status; + sendSignal(senderRef, GSN_CREATE_TABLE_REF, signal, + CreateTableRef::SignalLength, JBB); +} + +void +Dbdict::execALTER_TABLE_REQ(Signal* signal) +{ + // Received by master + jamEntry(); + if(!assembleFragments(signal)){ + return; + } + AlterTableReq* const req = (AlterTableReq*)signal->getDataPtr(); + const Uint32 senderRef = req->senderRef; + const Uint32 senderData = req->senderData; + const Uint32 changeMask = req->changeMask; + const Uint32 tableId = req->tableId; + const Uint32 tableVersion = req->tableVersion; + ParseDictTabInfoRecord* aParseRecord; + + // Get table definition + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId, false); + if(tablePtr.isNull()){ + jam(); + alterTableRef(signal, req, AlterTableRef::NoSuchTable); + return; + } + + if(getOwnNodeId() != c_masterNodeId){ + jam(); + alterTableRef(signal, req, AlterTableRef::NotMaster); + return; + } + + if(c_blockState != BS_IDLE){ + jam(); + alterTableRef(signal, req, AlterTableRef::Busy); + return; + } + + const TableRecord::TabState tabState = tablePtr.p->tabState; + bool ok = false; + switch(tabState){ + case TableRecord::NOT_DEFINED: + case TableRecord::REORG_TABLE_PREPARED: + case TableRecord::DEFINING: + case TableRecord::CHECKED: + jam(); + alterTableRef(signal, req, AlterTableRef::NoSuchTable); + return; + case TableRecord::DEFINED: + ok = true; + jam(); + break; + case TableRecord::PREPARE_DROPPING: + case TableRecord::DROPPING: + jam(); + alterTableRef(signal, req, AlterTableRef::DropInProgress); + return; + } + ndbrequire(ok); + + if(tablePtr.p->tableVersion != tableVersion){ + jam(); + alterTableRef(signal, req, AlterTableRef::InvalidTableVersion); + return; + } + // Parse new table defintion + ParseDictTabInfoRecord parseRecord; + aParseRecord = &parseRecord; + + CreateTableRecordPtr alterTabPtr; // Reuse create table records + c_opCreateTable.seize(alterTabPtr); + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + + if(alterTabPtr.isNull()){ + jam(); + alterTableRef(signal, req, AlterTableRef::Busy); + return; + } + + regAlterTabPtr->m_changeMask = changeMask; + parseRecord.requestType = DictTabInfo::AlterTableFromAPI; + parseRecord.errorCode = 0; + + SegmentedSectionPtr ptr; + signal->getSection(ptr, AlterTableReq::DICT_TAB_INFO); + SimplePropertiesSectionReader r(ptr, getSectionSegmentPool()); + + handleTabInfoInit(r, &parseRecord, false); // Will not save info + + if(parseRecord.errorCode != 0){ + jam(); + c_opCreateTable.release(alterTabPtr); + alterTableRef(signal, req, + (AlterTableRef::ErrorCode) parseRecord.errorCode, + aParseRecord); + return; + } + + releaseSections(signal); + regAlterTabPtr->key = ++c_opRecordSequence; + c_opCreateTable.add(alterTabPtr); + ndbrequire(c_opCreateTable.find(alterTabPtr, regAlterTabPtr->key)); + regAlterTabPtr->m_errorCode = 0; + regAlterTabPtr->m_senderRef = senderRef; + regAlterTabPtr->m_senderData = senderData; + regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i; + regAlterTabPtr->m_alterTableFailed = false; + regAlterTabPtr->m_coordinatorRef = reference(); + regAlterTabPtr->m_fragmentsPtrI = RNIL; + regAlterTabPtr->m_dihAddFragPtr = RNIL; + + // Alter table on all nodes + c_blockState = BS_BUSY; + + // Send prepare request to all alive nodes + SimplePropertiesSectionWriter w(getSectionSegmentPool()); + packTableIntoPagesImpl(w, parseRecord.tablePtr); + + SegmentedSectionPtr tabInfoPtr; + w.getPtr(tabInfoPtr); + signal->setSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + + AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); + lreq->senderRef = reference(); + lreq->senderData = regAlterTabPtr->key; + lreq->clientRef = regAlterTabPtr->m_senderRef; + lreq->clientData = regAlterTabPtr->m_senderData; + lreq->changeMask = changeMask; + lreq->tableId = tableId; + lreq->tableVersion = tableVersion + 1; + lreq->gci = tablePtr.p->gciTableCreated; + lreq->requestType = AlterTabReq::AlterTablePrepare; + + sendSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + +} + +void Dbdict::alterTableRef(Signal * signal, + AlterTableReq * req, + AlterTableRef::ErrorCode errCode, + ParseDictTabInfoRecord* parseRecord) +{ + jam(); + releaseSections(signal); + AlterTableRef * ref = (AlterTableRef*)signal->getDataPtrSend(); + Uint32 senderRef = req->senderRef; + ref->senderData = req->senderData; + ref->senderRef = reference(); + ref->masterNodeId = c_masterNodeId; + if (parseRecord) { + ref->errorCode = parseRecord->errorCode; + ref->errorLine = parseRecord->errorLine; + ref->errorKey = parseRecord->errorKey; + ref->status = parseRecord->status; + } + else { + ref->errorCode = errCode; + ref->errorLine = 0; + ref->errorKey = 0; + ref->status = 0; + } + sendSignal(senderRef, GSN_ALTER_TABLE_REF, signal, + AlterTableRef::SignalLength, JBB); +} + +void +Dbdict::execALTER_TAB_REQ(Signal * signal) +{ + // Received in all nodes to handle change locally + jamEntry(); + + if(!assembleFragments(signal)){ + return; + } + AlterTabReq* const req = (AlterTabReq*)signal->getDataPtr(); + const Uint32 senderRef = req->senderRef; + const Uint32 senderData = req->senderData; + const Uint32 changeMask = req->changeMask; + const Uint32 tableId = req->tableId; + const Uint32 tableVersion = req->tableVersion; + const Uint32 gci = req->gci; + AlterTabReq::RequestType requestType = + (AlterTabReq::RequestType) req->requestType; + + SegmentedSectionPtr tabInfoPtr; + signal->getSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO); + + CreateTableRecordPtr alterTabPtr; // Reuse create table records + + if (senderRef != reference()) { + jam(); + c_blockState = BS_BUSY; + } + if ((requestType == AlterTabReq::AlterTablePrepare) + && (senderRef != reference())) { + jam(); + c_opCreateTable.seize(alterTabPtr); + if(!alterTabPtr.isNull()) + alterTabPtr.p->m_changeMask = changeMask; + } + else { + jam(); + ndbrequire(c_opCreateTable.find(alterTabPtr, senderData)); + } + if(alterTabPtr.isNull()){ + jam(); + alterTabRef(signal, req, AlterTableRef::Busy); + return; + } + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + regAlterTabPtr->m_alterTableId = tableId; + regAlterTabPtr->m_coordinatorRef = senderRef; + + // Get table definition + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId, false); + if(tablePtr.isNull()){ + jam(); + alterTabRef(signal, req, AlterTableRef::NoSuchTable); + return; + } + + switch(requestType) { + case(AlterTabReq::AlterTablePrepare): { + ParseDictTabInfoRecord* aParseRecord; + + const TableRecord::TabState tabState = tablePtr.p->tabState; + bool ok = false; + switch(tabState){ + case TableRecord::NOT_DEFINED: + case TableRecord::REORG_TABLE_PREPARED: + case TableRecord::DEFINING: + case TableRecord::CHECKED: + jam(); + alterTabRef(signal, req, AlterTableRef::NoSuchTable); + return; + case TableRecord::DEFINED: + ok = true; + jam(); + break; + case TableRecord::PREPARE_DROPPING: + case TableRecord::DROPPING: + jam(); + alterTabRef(signal, req, AlterTableRef::DropInProgress); + return; + } + ndbrequire(ok); + + if(tablePtr.p->tableVersion + 1 != tableVersion){ + jam(); + alterTabRef(signal, req, AlterTableRef::InvalidTableVersion); + return; + } + TableRecordPtr newTablePtr; + if (senderRef != reference()) { + jam(); + // Parse altered table defintion + ParseDictTabInfoRecord parseRecord; + aParseRecord = &parseRecord; + + parseRecord.requestType = DictTabInfo::AlterTableFromAPI; + parseRecord.errorCode = 0; + + SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool()); + + handleTabInfoInit(r, &parseRecord, false); // Will not save info + + if(parseRecord.errorCode != 0){ + jam(); + c_opCreateTable.release(alterTabPtr); + alterTabRef(signal, req, + (AlterTableRef::ErrorCode) parseRecord.errorCode, + aParseRecord); + return; + } + regAlterTabPtr->key = senderData; + c_opCreateTable.add(alterTabPtr); + regAlterTabPtr->m_errorCode = 0; + regAlterTabPtr->m_senderRef = senderRef; + regAlterTabPtr->m_senderData = senderData; + regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i; + regAlterTabPtr->m_fragmentsPtrI = RNIL; + regAlterTabPtr->m_dihAddFragPtr = RNIL; + newTablePtr = parseRecord.tablePtr; + newTablePtr.p->tableVersion = tableVersion; + } + else { // (req->senderRef == reference()) + jam(); + c_tableRecordPool.getPtr(newTablePtr, regAlterTabPtr->m_tablePtrI); + newTablePtr.p->tableVersion = tableVersion; + } + if (handleAlterTab(req, regAlterTabPtr, tablePtr, newTablePtr) == -1) { + jam(); + c_opCreateTable.release(alterTabPtr); + alterTabRef(signal, req, AlterTableRef::UnsupportedChange); + return; + } + releaseSections(signal); + // Propagate alter table to other local blocks + AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = senderData; + req->changeMask = changeMask; + req->tableId = tableId; + req->tableVersion = tableVersion; + req->gci = gci; + req->requestType = requestType; + sendSignal(DBLQH_REF, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + return; + } + case(AlterTabReq::AlterTableCommit): { + jam(); + // Write schema for altered table to disk + SegmentedSectionPtr tabInfoPtr; + signal->getSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO); + regAlterTabPtr->m_tabInfoPtrI = tabInfoPtr.i; + + signal->header.m_noOfSections = 0; + + // Update table record + tablePtr.p->packedSize = tabInfoPtr.sz; + tablePtr.p->tableVersion = tableVersion; + tablePtr.p->gciTableCreated = gci; + + SchemaFile::TableEntry tabEntry; + tabEntry.m_tableVersion = tableVersion; + tabEntry.m_tableType = tablePtr.p->tableType; + tabEntry.m_tableState = SchemaFile::ALTER_TABLE_COMMITTED; + tabEntry.m_gcp = gci; + tabEntry.m_noOfPages = + DIV(tabInfoPtr.sz + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS); + + Callback callback; + callback.m_callbackData = senderData; + callback.m_callbackFunction = + safe_cast(&Dbdict::alterTab_writeSchemaConf); + + updateSchemaState(signal, tableId, &tabEntry, &callback); + break; + } + case(AlterTabReq::AlterTableRevert): { + jam(); + // Revert failed alter table + revertAlterTable(signal, changeMask, tableId, regAlterTabPtr); + // Acknowledge the reverted alter table + AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + conf->changeMask = changeMask; + conf->tableId = tableId; + conf->tableVersion = tableVersion; + conf->gci = gci; + conf->requestType = requestType; + sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal, + AlterTabConf::SignalLength, JBB); + break; + } + default: ndbrequire(false); + } +} + +void Dbdict::alterTabRef(Signal * signal, + AlterTabReq * req, + AlterTableRef::ErrorCode errCode, + ParseDictTabInfoRecord* parseRecord) +{ + jam(); + releaseSections(signal); + AlterTabRef * ref = (AlterTabRef*)signal->getDataPtrSend(); + Uint32 senderRef = req->senderRef; + ref->senderData = req->senderData; + ref->senderRef = reference(); + if (parseRecord) { + jam(); + ref->errorCode = parseRecord->errorCode; + ref->errorLine = parseRecord->errorLine; + ref->errorKey = parseRecord->errorKey; + ref->errorStatus = parseRecord->status; + } + else { + jam(); + ref->errorCode = errCode; + ref->errorLine = 0; + ref->errorKey = 0; + ref->errorStatus = 0; + } + sendSignal(senderRef, GSN_ALTER_TAB_REF, signal, + AlterTabRef::SignalLength, JBB); + + c_blockState = BS_IDLE; +} + +void Dbdict::execALTER_TAB_REF(Signal * signal){ + jamEntry(); + + AlterTabRef * ref = (AlterTabRef*)signal->getDataPtr(); + + Uint32 senderRef = ref->senderRef; + Uint32 senderData = ref->senderData; + Uint32 errorCode = ref->errorCode; + Uint32 errorLine = ref->errorLine; + Uint32 errorKey = ref->errorKey; + Uint32 errorStatus = ref->errorStatus; + AlterTabReq::RequestType requestType = + (AlterTabReq::RequestType) ref->requestType; + CreateTableRecordPtr alterTabPtr; + ndbrequire(c_opCreateTable.find(alterTabPtr, senderData)); + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + Uint32 changeMask = regAlterTabPtr->m_changeMask; + SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + safeCounter.clearWaitingFor(refToNode(senderRef)); + switch (requestType) { + case(AlterTabReq::AlterTablePrepare): { + if (safeCounter.done()) { + jam(); + // Send revert request to all alive nodes + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId); + Uint32 tableId = tablePtr.p->tableId; + Uint32 tableVersion = tablePtr.p->tableVersion; + Uint32 gci = tablePtr.p->gciTableCreated; + SimplePropertiesSectionWriter w(getSectionSegmentPool()); + packTableIntoPagesImpl(w, tablePtr); + SegmentedSectionPtr spDataPtr; + w.getPtr(spDataPtr); + signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + + AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); + lreq->senderRef = reference(); + lreq->senderData = regAlterTabPtr->key; + lreq->clientRef = regAlterTabPtr->m_senderRef; + lreq->clientData = regAlterTabPtr->m_senderData; + lreq->changeMask = changeMask; + lreq->tableId = tableId; + lreq->tableVersion = tableVersion; + lreq->gci = gci; + lreq->requestType = AlterTabReq::AlterTableRevert; + + sendSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + } + else { + jam(); + regAlterTabPtr->m_alterTableFailed = true; + } + break; + } + case(AlterTabReq::AlterTableCommit): + jam(); + case(AlterTabReq::AlterTableRevert): { + AlterTableRef * apiRef = (AlterTableRef*)signal->getDataPtrSend(); + + apiRef->senderData = senderData; + apiRef->senderRef = reference(); + apiRef->masterNodeId = c_masterNodeId; + apiRef->errorCode = errorCode; + apiRef->errorLine = errorLine; + apiRef->errorKey = errorKey; + apiRef->status = errorStatus; + if (safeCounter.done()) { + jam(); + sendSignal(senderRef, GSN_ALTER_TABLE_REF, signal, + AlterTableRef::SignalLength, JBB); + c_blockState = BS_IDLE; + } + else { + jam(); + regAlterTabPtr->m_alterTableFailed = true; + regAlterTabPtr->m_alterTableRef = *apiRef; + } + break; + } + default: ndbrequire(false); + } +} + +void +Dbdict::execALTER_TAB_CONF(Signal * signal){ + jamEntry(); + AlterTabConf * const conf = (AlterTabConf*)signal->getDataPtr(); + Uint32 senderRef = conf->senderRef; + Uint32 senderData = conf->senderData; + Uint32 changeMask = conf->changeMask; + Uint32 tableId = conf->tableId; + Uint32 tableVersion = conf->tableVersion; + Uint32 gci = conf->gci; + AlterTabReq::RequestType requestType = + (AlterTabReq::RequestType) conf->requestType; + CreateTableRecordPtr alterTabPtr; + ndbrequire(c_opCreateTable.find(alterTabPtr, senderData)); + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + + switch (requestType) { + case(AlterTabReq::AlterTablePrepare): { + switch(refToBlock(signal->getSendersBlockRef())) { + case DBLQH: { + jam(); + AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = senderData; + req->changeMask = changeMask; + req->tableId = tableId; + req->tableVersion = tableVersion; + req->gci = gci; + req->requestType = requestType; + sendSignal(DBDIH_REF, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + return; + } + case DBDIH: { + jam(); + AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = senderData; + req->changeMask = changeMask; + req->tableId = tableId; + req->tableVersion = tableVersion; + req->gci = gci; + req->requestType = requestType; + sendSignal(DBTC_REF, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + return; + } + case DBTC: { + jam(); + // Participant is done with prepare phase, send conf to coordinator + AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = senderData; + conf->changeMask = changeMask; + conf->tableId = tableId; + conf->tableVersion = tableVersion; + conf->gci = gci; + conf->requestType = requestType; + sendSignal(regAlterTabPtr->m_coordinatorRef, GSN_ALTER_TAB_CONF, signal, + AlterTabConf::SignalLength, JBB); + return; + } + default :break; + } + // Coordinator only + SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + safeCounter.clearWaitingFor(refToNode(senderRef)); + if (safeCounter.done()) { + jam(); + // We have received all local confirmations + if (regAlterTabPtr->m_alterTableFailed) { + jam(); + // Send revert request to all alive nodes + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId); + Uint32 tableId = tablePtr.p->tableId; + Uint32 tableVersion = tablePtr.p->tableVersion; + Uint32 gci = tablePtr.p->gciTableCreated; + SimplePropertiesSectionWriter w(getSectionSegmentPool()); + packTableIntoPagesImpl(w, tablePtr); + SegmentedSectionPtr spDataPtr; + w.getPtr(spDataPtr); + signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + + AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); + lreq->senderRef = reference(); + lreq->senderData = regAlterTabPtr->key; + lreq->clientRef = regAlterTabPtr->m_senderRef; + lreq->clientData = regAlterTabPtr->m_senderData; + lreq->changeMask = changeMask; + lreq->tableId = tableId; + lreq->tableVersion = tableVersion; + lreq->gci = gci; + lreq->requestType = AlterTabReq::AlterTableRevert; + + sendSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + } + else { + jam(); + // Send commit request to all alive nodes + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + SimplePropertiesSectionWriter w(getSectionSegmentPool()); + packTableIntoPagesImpl(w, tablePtr); + SegmentedSectionPtr spDataPtr; + w.getPtr(spDataPtr); + signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + + AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); + lreq->senderRef = reference(); + lreq->senderData = regAlterTabPtr->key; + lreq->clientRef = regAlterTabPtr->m_senderRef; + lreq->clientData = regAlterTabPtr->m_senderData; + lreq->changeMask = changeMask; + lreq->tableId = tableId; + lreq->tableVersion = tableVersion; + lreq->gci = gci; + lreq->requestType = AlterTabReq::AlterTableCommit; + + sendSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); + } + } + else { + // (!safeCounter.done()) + jam(); + } + break; + } + case(AlterTabReq::AlterTableRevert): + jam(); + case(AlterTabReq::AlterTableCommit): { + SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + safeCounter.clearWaitingFor(refToNode(senderRef)); + if (safeCounter.done()) { + jam(); + // We have received all local confirmations + releaseSections(signal); + if (regAlterTabPtr->m_alterTableFailed) { + jam(); + AlterTableRef * apiRef = + (AlterTableRef*)signal->getDataPtrSend(); + *apiRef = regAlterTabPtr->m_alterTableRef; + sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_REF, signal, + AlterTableRef::SignalLength, JBB); + } + else { + jam(); + // Alter table completed, inform API + AlterTableConf * const apiConf = + (AlterTableConf*)signal->getDataPtrSend(); + apiConf->senderRef = reference(); + apiConf->senderData = regAlterTabPtr->m_senderData; + apiConf->tableId = tableId; + apiConf->tableVersion = tableVersion; + + //@todo check api failed + sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_CONF, signal, + AlterTableConf::SignalLength, JBB); + } + + // Release resources + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI); + releaseTableObject(tabPtr.i, false); + c_opCreateTable.release(alterTabPtr); + c_blockState = BS_IDLE; + } + else { + // (!safeCounter.done()) + jam(); + } + break; + } + default: ndbrequire(false); + } +} + +// For debugging +inline +void Dbdict::printTables() +{ + DLHashTable<TableRecord>::Iterator iter; + bool moreTables = c_tableRecordHash.first(iter); + printf("TABLES IN DICT:\n"); + while (moreTables) { + TableRecordPtr tablePtr = iter.curr; + printf("%s ", tablePtr.p->tableName); + moreTables = c_tableRecordHash.next(iter); + } + printf("\n"); +} + +int Dbdict::handleAlterTab(AlterTabReq * req, + CreateTableRecord * regAlterTabPtr, + TableRecordPtr origTablePtr, + TableRecordPtr newTablePtr) +{ + Uint32 changeMask = req->changeMask; + + if (AlterTableReq::getNameFlag(changeMask)) { + jam(); + // Table rename + // Remove from hashtable +#ifdef VM_TRACE + TableRecordPtr tmp; + ndbrequire(c_tableRecordHash.find(tmp, *origTablePtr.p)); +#endif + c_tableRecordHash.remove(origTablePtr); + strcpy(regAlterTabPtr->previousTableName, origTablePtr.p->tableName); + strcpy(origTablePtr.p->tableName, newTablePtr.p->tableName); + // Set new schema version + origTablePtr.p->tableVersion = newTablePtr.p->tableVersion; + // Put it back +#ifdef VM_TRACE + ndbrequire(!c_tableRecordHash.find(tmp, *origTablePtr.p)); +#endif + c_tableRecordHash.add(origTablePtr); + + return 0; + } + jam(); + return -1; +} + +void Dbdict::revertAlterTable(Signal * signal, + Uint32 changeMask, + Uint32 tableId, + CreateTableRecord * regAlterTabPtr) +{ + if (AlterTableReq::getNameFlag(changeMask)) { + jam(); + // Table rename + // Restore previous name + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + // Remove from hashtable +#ifdef VM_TRACE + TableRecordPtr tmp; + ndbrequire(c_tableRecordHash.find(tmp, * tablePtr.p)); +#endif + c_tableRecordHash.remove(tablePtr); + // Restore name + strcpy(tablePtr.p->tableName, regAlterTabPtr->previousTableName); + // Revert schema version + tablePtr.p->tableVersion = tablePtr.p->tableVersion - 1; + // Put it back +#ifdef VM_TRACE + ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p)); +#endif + c_tableRecordHash.add(tablePtr); + + return; + } + + ndbrequire(false); +} + +void +Dbdict::alterTab_writeSchemaConf(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + Uint32 key = callbackData; + CreateTableRecordPtr alterTabPtr; + ndbrequire(c_opCreateTable.find(alterTabPtr, key)); + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + Uint32 tableId = regAlterTabPtr->m_alterTableId; + + Callback callback; + callback.m_callbackData = regAlterTabPtr->key; + callback.m_callbackFunction = + safe_cast(&Dbdict::alterTab_writeTableConf); + + SegmentedSectionPtr tabInfoPtr; + getSection(tabInfoPtr, regAlterTabPtr->m_tabInfoPtrI); + + writeTableFile(signal, tableId, tabInfoPtr, &callback); + + signal->setSection(tabInfoPtr, 0); + releaseSections(signal); +} + +void +Dbdict::alterTab_writeTableConf(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + CreateTableRecordPtr alterTabPtr; + ndbrequire(c_opCreateTable.find(alterTabPtr, callbackData)); + CreateTableRecord * regAlterTabPtr = alterTabPtr.p; + Uint32 coordinatorRef = regAlterTabPtr->m_coordinatorRef; + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_alterTableId); + + // Alter table commit request handled successfully + AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = callbackData; + conf->tableId = tabPtr.p->tableId; + conf->tableVersion = tabPtr.p->tableVersion; + conf->gci = tabPtr.p->gciTableCreated; + conf->requestType = AlterTabReq::AlterTableCommit; + sendSignal(coordinatorRef, GSN_ALTER_TAB_CONF, signal, + AlterTabConf::SignalLength, JBB); + if(coordinatorRef != reference()) { + jam(); + // Release resources + c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI); + releaseTableObject(tabPtr.i, false); + c_opCreateTable.release(alterTabPtr); + c_blockState = BS_IDLE; + } +} + +void +Dbdict::execCREATE_FRAGMENTATION_REF(Signal * signal){ + jamEntry(); + const Uint32 * theData = signal->getDataPtr(); + CreateFragmentationRef * const ref = (CreateFragmentationRef*)theData; + (void)ref; + ndbrequire(false); +} + +void +Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){ + jamEntry(); + const Uint32 * theData = signal->getDataPtr(); + CreateFragmentationConf * const conf = (CreateFragmentationConf*)theData; + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData)); + + ndbrequire(signal->getNoOfSections() == 1); + + SegmentedSectionPtr fragDataPtr; + signal->getSection(fragDataPtr, CreateFragmentationConf::FRAGMENTS); + signal->header.m_noOfSections = 0; + + /** + * Get table + */ + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + /** + * Save fragment count + */ + tabPtr.p->fragmentCount = conf->noOfFragments; + + /** + * Update table version + */ + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + SchemaFile::TableEntry * tabEntry = getTableEntry(pagePtr.p, tabPtr.i); + + tabPtr.p->tableVersion = tabEntry->m_tableVersion + 1; + + /** + * Pack + */ + SimplePropertiesSectionWriter w(getSectionSegmentPool()); + packTableIntoPagesImpl(w, tabPtr); + + SegmentedSectionPtr spDataPtr; + w.getPtr(spDataPtr); + + signal->setSection(spDataPtr, CreateTabReq::DICT_TAB_INFO); + signal->setSection(fragDataPtr, CreateTabReq::FRAGMENTATION); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter); + createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ; + createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTablePrepare; + tmp.init<CreateTabRef>(rg, GSN_CREATE_TAB_REF, createTabPtr.p->key); + + CreateTabReq * const req = (CreateTabReq*)theData; + req->senderRef = reference(); + req->senderData = createTabPtr.p->key; + req->clientRef = createTabPtr.p->m_senderRef; + req->clientData = createTabPtr.p->m_senderData; + req->requestType = CreateTabReq::CreateTablePrepare; + + req->gci = 0; + req->tableId = tabPtr.i; + req->tableVersion = tabEntry->m_tableVersion + 1; + + sendFragmentedSignal(rg, GSN_CREATE_TAB_REQ, signal, + CreateTabReq::SignalLength, JBB); + + return; +} + +void +Dbdict::execCREATE_TAB_REF(Signal* signal){ + jamEntry(); + + CreateTabRef * const ref = (CreateTabRef*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData)); + + ndbrequire(createTabPtr.p->m_coordinatorRef == reference()); + ndbrequire(createTabPtr.p->m_coordinatorData.m_gsn == GSN_CREATE_TAB_REQ); + + if(ref->errorCode != CreateTabRef::NF_FakeErrorREF){ + createTabPtr.p->setErrorCode(ref->errorCode); + } + createTab_reply(signal, createTabPtr, refToNode(ref->senderRef)); +} + +void +Dbdict::execCREATE_TAB_CONF(Signal* signal){ + jamEntry(); + + ndbrequire(signal->getNoOfSections() == 0); + + CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData)); + + ndbrequire(createTabPtr.p->m_coordinatorRef == reference()); + ndbrequire(createTabPtr.p->m_coordinatorData.m_gsn == GSN_CREATE_TAB_REQ); + + createTab_reply(signal, createTabPtr, refToNode(conf->senderRef)); +} + +void +Dbdict::createTab_reply(Signal* signal, + CreateTableRecordPtr createTabPtr, + Uint32 nodeId) +{ + + SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter); + if(!tmp.clearWaitingFor(nodeId)){ + jam(); + return; + } + + switch(createTabPtr.p->m_coordinatorData.m_requestType){ + case CreateTabReq::CreateTablePrepare:{ + + if(createTabPtr.p->m_errorCode != 0){ + jam(); + /** + * Failed to prepare on atleast one node -> abort on all + */ + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ; + createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTableDrop; + ndbrequire(tmp.init<CreateTabRef>(rg, createTabPtr.p->key)); + + CreateTabReq * const req = (CreateTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = createTabPtr.p->key; + req->requestType = CreateTabReq::CreateTableDrop; + + sendSignal(rg, GSN_CREATE_TAB_REQ, signal, + CreateTabReq::SignalLength, JBB); + return; + } + + /** + * Lock mutex before commiting table + */ + Mutex mutex(signal, c_mutexMgr, createTabPtr.p->m_startLcpMutex); + Callback c = { safe_cast(&Dbdict::createTab_startLcpMutex_locked), + createTabPtr.p->key}; + + ndbrequire(mutex.lock(c)); + return; + } + case CreateTabReq::CreateTableCommit:{ + jam(); + ndbrequire(createTabPtr.p->m_errorCode == 0); + + /** + * Unlock mutex before commiting table + */ + Mutex mutex(signal, c_mutexMgr, createTabPtr.p->m_startLcpMutex); + Callback c = { safe_cast(&Dbdict::createTab_startLcpMutex_unlocked), + createTabPtr.p->key}; + mutex.unlock(c); + return; + } + case CreateTabReq::CreateTableDrop:{ + jam(); + CreateTableRef * const ref = (CreateTableRef*)signal->getDataPtr(); + ref->senderRef = reference(); + ref->senderData = createTabPtr.p->m_senderData; + ref->errorCode = createTabPtr.p->m_errorCode; + ref->masterNodeId = c_masterNodeId; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = 0; + + //@todo check api failed + sendSignal(createTabPtr.p->m_senderRef, GSN_CREATE_TABLE_REF, signal, + CreateTableRef::SignalLength, JBB); + c_opCreateTable.release(createTabPtr); + c_blockState = BS_IDLE; + return; + } + } + ndbrequire(false); +} + +void +Dbdict::createTab_startLcpMutex_locked(Signal* signal, + Uint32 callbackData, + Uint32 retValue){ + jamEntry(); + + ndbrequire(retValue == 0); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ; + createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTableCommit; + SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter); + tmp.init<CreateTabRef>(rg, GSN_CREATE_TAB_REF, createTabPtr.p->key); + + CreateTabReq * const req = (CreateTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = createTabPtr.p->key; + req->requestType = CreateTabReq::CreateTableCommit; + + sendSignal(rg, GSN_CREATE_TAB_REQ, signal, + CreateTabReq::SignalLength, JBB); +} + +void +Dbdict::createTab_startLcpMutex_unlocked(Signal* signal, + Uint32 callbackData, + Uint32 retValue){ + jamEntry(); + + ndbrequire(retValue == 0); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + createTabPtr.p->m_startLcpMutex.release(c_mutexMgr); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + CreateTableConf * const conf = (CreateTableConf*)signal->getDataPtr(); + conf->senderRef = reference(); + conf->senderData = createTabPtr.p->m_senderData; + conf->tableId = createTabPtr.p->m_tablePtrI; + conf->tableVersion = tabPtr.p->tableVersion; + + //@todo check api failed + sendSignal(createTabPtr.p->m_senderRef, GSN_CREATE_TABLE_CONF, signal, + CreateTableConf::SignalLength, JBB); + c_opCreateTable.release(createTabPtr); + c_blockState = BS_IDLE; + return; +} + +/*********************************************************** + * CreateTable participant code + **********************************************************/ +void +Dbdict::execCREATE_TAB_REQ(Signal* signal){ + jamEntry(); + + if(!assembleFragments(signal)){ + jam(); + return; + } + + CreateTabReq * const req = (CreateTabReq*)signal->getDataPtr(); + + CreateTabReq::RequestType rt = (CreateTabReq::RequestType)req->requestType; + switch(rt){ + case CreateTabReq::CreateTablePrepare: + CRASH_INSERTION2(6003, getOwnNodeId() != c_masterNodeId); + createTab_prepare(signal, req); + return; + case CreateTabReq::CreateTableCommit: + CRASH_INSERTION2(6004, getOwnNodeId() != c_masterNodeId); + createTab_commit(signal, req); + return; + case CreateTabReq::CreateTableDrop: + CRASH_INSERTION2(6005, getOwnNodeId() != c_masterNodeId); + createTab_drop(signal, req); + return; + } + ndbrequire(false); +} + +void +Dbdict::createTab_prepare(Signal* signal, CreateTabReq * req){ + + const Uint32 gci = req->gci; + const Uint32 tableId = req->tableId; + const Uint32 tableVersion = req->tableVersion; + + SegmentedSectionPtr tabInfoPtr; + signal->getSection(tabInfoPtr, CreateTabReq::DICT_TAB_INFO); + + CreateTableRecordPtr createTabPtr; + if(req->senderRef == reference()){ + jam(); + ndbrequire(c_opCreateTable.find(createTabPtr, req->senderData)); + } else { + jam(); + c_opCreateTable.seize(createTabPtr); + + ndbrequire(!createTabPtr.isNull()); + + createTabPtr.p->key = req->senderData; + c_opCreateTable.add(createTabPtr); + createTabPtr.p->m_errorCode = 0; + createTabPtr.p->m_tablePtrI = tableId; + createTabPtr.p->m_coordinatorRef = req->senderRef; + createTabPtr.p->m_senderRef = req->clientRef; + createTabPtr.p->m_senderData = req->clientData; + createTabPtr.p->m_dihAddFragPtr = RNIL; + + /** + * Put data into table record + */ + ParseDictTabInfoRecord parseRecord; + parseRecord.requestType = DictTabInfo::AddTableFromDict; + parseRecord.errorCode = 0; + + SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool()); + + handleTabInfoInit(r, &parseRecord); + + ndbrequire(parseRecord.errorCode == 0); + } + + ndbrequire(!createTabPtr.isNull()); + + SegmentedSectionPtr fragPtr; + signal->getSection(fragPtr, CreateTabReq::FRAGMENTATION); + + createTabPtr.p->m_tabInfoPtrI = tabInfoPtr.i; + createTabPtr.p->m_fragmentsPtrI = fragPtr.i; + + signal->header.m_noOfSections = 0; + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, tableId); + tabPtr.p->packedSize = tabInfoPtr.sz; + tabPtr.p->tableVersion = tableVersion; + tabPtr.p->gciTableCreated = gci; + + SchemaFile::TableEntry tabEntry; + tabEntry.m_tableVersion = tableVersion; + tabEntry.m_tableType = tabPtr.p->tableType; + tabEntry.m_tableState = SchemaFile::ADD_STARTED; + tabEntry.m_gcp = gci; + tabEntry.m_noOfPages = + DIV(tabInfoPtr.sz + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS); + + Callback callback; + callback.m_callbackData = createTabPtr.p->key; + callback.m_callbackFunction = + safe_cast(&Dbdict::createTab_writeSchemaConf1); + + updateSchemaState(signal, tableId, &tabEntry, &callback); +} + +void getSection(SegmentedSectionPtr & ptr, Uint32 i); + +void +Dbdict::createTab_writeSchemaConf1(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + Callback callback; + callback.m_callbackData = createTabPtr.p->key; + callback.m_callbackFunction = + safe_cast(&Dbdict::createTab_writeTableConf); + + SegmentedSectionPtr tabInfoPtr; + getSection(tabInfoPtr, createTabPtr.p->m_tabInfoPtrI); + writeTableFile(signal, createTabPtr.p->m_tablePtrI, tabInfoPtr, &callback); + + createTabPtr.p->m_tabInfoPtrI = RNIL; + signal->setSection(tabInfoPtr, 0); + releaseSections(signal); +} + +void +Dbdict::createTab_writeTableConf(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + SegmentedSectionPtr fragDataPtr; + getSection(fragDataPtr, createTabPtr.p->m_fragmentsPtrI); + + Callback callback; + callback.m_callbackData = callbackData; + callback.m_callbackFunction = + safe_cast(&Dbdict::createTab_dihComplete); + + createTab_dih(signal, createTabPtr, fragDataPtr, &callback); +} + +void +Dbdict::createTab_dih(Signal* signal, + CreateTableRecordPtr createTabPtr, + SegmentedSectionPtr fragDataPtr, + Callback * c){ + jam(); + + createTabPtr.p->m_callback = * c; + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + DiAddTabReq * req = (DiAddTabReq*)signal->getDataPtrSend(); + req->connectPtr = createTabPtr.p->key; + req->tableId = tabPtr.i; + req->fragType = tabPtr.p->fragmentType; + req->kValue = tabPtr.p->kValue; + req->noOfReplicas = 0; + req->storedTable = tabPtr.p->storedTable; + req->tableType = tabPtr.p->tableType; + req->schemaVersion = tabPtr.p->tableVersion; + req->primaryTableId = tabPtr.p->primaryTableId; + + if(!fragDataPtr.isNull()){ + signal->setSection(fragDataPtr, DiAddTabReq::FRAGMENTATION); + } + + sendSignal(DBDIH_REF, GSN_DIADDTABREQ, signal, + DiAddTabReq::SignalLength, JBB); +} + +static +void +calcLHbits(Uint32 * lhPageBits, Uint32 * lhDistrBits, + Uint32 fid, Uint32 totalFragments) +{ + Uint32 distrBits = 0; + Uint32 pageBits = 0; + + Uint32 tmp = 1; + while (tmp < totalFragments) { + jam(); + tmp <<= 1; + distrBits++; + }//while + if (tmp != totalFragments) { + tmp >>= 1; + if ((fid >= (totalFragments - tmp)) && (fid < (tmp - 1))) { + distrBits--; + }//if + }//if + * lhPageBits = pageBits; + * lhDistrBits = distrBits; + +}//calcLHbits() + + +void +Dbdict::execADD_FRAGREQ(Signal* signal) { + jamEntry(); + + AddFragReq * const req = (AddFragReq*)signal->getDataPtr(); + + Uint32 dihPtr = req->dihPtr; + Uint32 senderData = req->senderData; + Uint32 tableId = req->tableId; + Uint32 fragId = req->fragmentId; + Uint32 node = req->nodeId; + Uint32 lcpNo = req->nextLCP; + Uint32 fragCount = req->totalFragments; + Uint32 requestInfo = req->requestInfo; + Uint32 startGci = req->startGci; + + ndbrequire(node == getOwnNodeId()); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, senderData)); + + createTabPtr.p->m_dihAddFragPtr = dihPtr; + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, tableId); + +#if 0 + tabPtr.p->gciTableCreated = (startGci > tabPtr.p->gciTableCreated ? startGci: + startGci > tabPtr.p->gciTableCreated); +#endif + + /** + * Calc lh3PageBits + */ + Uint32 lhDistrBits = 0; + Uint32 lhPageBits = 0; + ::calcLHbits(&lhPageBits, &lhDistrBits, fragId, fragCount); + + { + LqhFragReq* req = (LqhFragReq*)signal->getDataPtrSend(); + req->senderData = senderData; + req->senderRef = reference(); + req->fragmentId = fragId; + req->requestInfo = requestInfo; + req->tableId = tableId; + req->localKeyLength = tabPtr.p->localKeyLen; + req->maxLoadFactor = tabPtr.p->maxLoadFactor; + req->minLoadFactor = tabPtr.p->minLoadFactor; + req->kValue = tabPtr.p->kValue; + req->lh3DistrBits = 0; //lhDistrBits; + req->lh3PageBits = 0; //lhPageBits; + req->noOfAttributes = tabPtr.p->noOfAttributes; + req->noOfNullAttributes = tabPtr.p->noOfNullBits; + req->noOfPagesToPreAllocate = 0; + req->schemaVersion = tabPtr.p->tableVersion; + Uint32 keyLen = tabPtr.p->tupKeyLength; + req->keyLength = keyLen; // wl-2066 no more "long keys" + req->nextLCP = lcpNo; + + req->noOfKeyAttr = tabPtr.p->noOfPrimkey; + req->noOfNewAttr = 0; + // noOfCharsets passed to TUP in upper half + req->noOfNewAttr |= (tabPtr.p->noOfCharsets << 16); + req->checksumIndicator = 1; + req->noOfAttributeGroups = 1; + req->GCPIndicator = 0; + req->startGci = startGci; + req->tableType = tabPtr.p->tableType; + req->primaryTableId = tabPtr.p->primaryTableId; + sendSignal(DBLQH_REF, GSN_LQHFRAGREQ, signal, + LqhFragReq::SignalLength, JBB); + } +} + +void +Dbdict::execLQHFRAGREF(Signal * signal){ + jamEntry(); + LqhFragRef * const ref = (LqhFragRef*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData)); + + createTabPtr.p->setErrorCode(ref->errorCode); + + { + AddFragRef * const ref = (AddFragRef*)signal->getDataPtr(); + ref->dihPtr = createTabPtr.p->m_dihAddFragPtr; + sendSignal(DBDIH_REF, GSN_ADD_FRAGREF, signal, + AddFragRef::SignalLength, JBB); + } +} + +void +Dbdict::execLQHFRAGCONF(Signal * signal){ + jamEntry(); + LqhFragConf * const conf = (LqhFragConf*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData)); + + createTabPtr.p->m_lqhFragPtr = conf->lqhFragPtr; + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + sendLQHADDATTRREQ(signal, createTabPtr, tabPtr.p->firstAttribute); +} + +void +Dbdict::sendLQHADDATTRREQ(Signal* signal, + CreateTableRecordPtr createTabPtr, + Uint32 attributePtrI){ + jam(); + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + LqhAddAttrReq * const req = (LqhAddAttrReq*)signal->getDataPtrSend(); + Uint32 i = 0; + for(i = 0; i<LqhAddAttrReq::MAX_ATTRIBUTES && attributePtrI != RNIL; i++){ + jam(); + AttributeRecordPtr attrPtr; + c_attributeRecordPool.getPtr(attrPtr, attributePtrI); + LqhAddAttrReq::Entry& entry = req->attributes[i]; + entry.attrId = attrPtr.p->attributeId; + entry.attrDescriptor = attrPtr.p->attributeDescriptor; + entry.extTypeInfo = 0; + // charset number passed to TUP, TUX in upper half + entry.extTypeInfo |= (attrPtr.p->extPrecision & ~0xFFFF); + if (tabPtr.p->isIndex()) { + Uint32 primaryAttrId; + if (attrPtr.p->nextAttrInTable != RNIL) { + getIndexAttr(tabPtr, attributePtrI, &primaryAttrId); + } else { + primaryAttrId = ZNIL; + if (tabPtr.p->isOrderedIndex()) + entry.attrId = 0; // attribute goes to TUP + } + entry.attrId |= (primaryAttrId << 16); + } + attributePtrI = attrPtr.p->nextAttrInTable; + } + req->lqhFragPtr = createTabPtr.p->m_lqhFragPtr; + req->senderData = createTabPtr.p->key; + req->senderAttrPtr = attributePtrI; + req->noOfAttributes = i; + + sendSignal(DBLQH_REF, GSN_LQHADDATTREQ, signal, + LqhAddAttrReq::HeaderLength + LqhAddAttrReq::EntryLength * i, JBB); +} + +void +Dbdict::execLQHADDATTREF(Signal * signal){ + jamEntry(); + LqhAddAttrRef * const ref = (LqhAddAttrRef*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData)); + + createTabPtr.p->setErrorCode(ref->errorCode); + + { + AddFragRef * const ref = (AddFragRef*)signal->getDataPtr(); + ref->dihPtr = createTabPtr.p->m_dihAddFragPtr; + sendSignal(DBDIH_REF, GSN_ADD_FRAGREF, signal, + AddFragRef::SignalLength, JBB); + } + +} + +void +Dbdict::execLQHADDATTCONF(Signal * signal){ + jamEntry(); + LqhAddAttrConf * const conf = (LqhAddAttrConf*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData)); + + const Uint32 fragId = conf->fragId; + const Uint32 nextAttrPtr = conf->senderAttrPtr; + if(nextAttrPtr != RNIL){ + jam(); + sendLQHADDATTRREQ(signal, createTabPtr, nextAttrPtr); + return; + } + + { + AddFragConf * const conf = (AddFragConf*)signal->getDataPtr(); + conf->dihPtr = createTabPtr.p->m_dihAddFragPtr; + conf->fragId = fragId; + sendSignal(DBDIH_REF, GSN_ADD_FRAGCONF, signal, + AddFragConf::SignalLength, JBB); + } +} + +void +Dbdict::execDIADDTABREF(Signal* signal){ + jam(); + + DiAddTabRef * const ref = (DiAddTabRef*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData)); + + createTabPtr.p->setErrorCode(ref->errorCode); + execute(signal, createTabPtr.p->m_callback, 0); +} + +void +Dbdict::execDIADDTABCONF(Signal* signal){ + jam(); + + DiAddTabConf * const conf = (DiAddTabConf*)signal->getDataPtr(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData)); + + signal->theData[0] = createTabPtr.p->key; + signal->theData[1] = reference(); + signal->theData[2] = createTabPtr.p->m_tablePtrI; + + if(createTabPtr.p->m_dihAddFragPtr != RNIL){ + jam(); + + /** + * We did perform at least one LQHFRAGREQ + */ + sendSignal(DBLQH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB); + return; + } else { + /** + * No local fragment (i.e. no LQHFRAGREQ) + */ + execute(signal, createTabPtr.p->m_callback, 0); + return; + //sendSignal(DBDIH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB); + } +} + +void +Dbdict::execTAB_COMMITREF(Signal* signal) { + jamEntry(); + ndbrequire(false); +}//execTAB_COMMITREF() + +void +Dbdict::execTAB_COMMITCONF(Signal* signal){ + jamEntry(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, signal->theData[0])); + + if(refToBlock(signal->getSendersBlockRef()) == DBLQH){ + + execute(signal, createTabPtr.p->m_callback, 0); + return; + } + + if(refToBlock(signal->getSendersBlockRef()) == DBDIH){ + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + signal->theData[0] = tabPtr.i; + signal->theData[1] = tabPtr.p->tableVersion; + signal->theData[2] = (Uint32)tabPtr.p->storedTable; + signal->theData[3] = reference(); + signal->theData[4] = (Uint32)tabPtr.p->tableType; + signal->theData[5] = createTabPtr.p->key; + signal->theData[6] = (Uint32)tabPtr.p->noOfPrimkey; + + Uint32 buf[2 * MAX_ATTRIBUTES_IN_INDEX]; + Uint32 sz = 0; + Uint32 tAttr = tabPtr.p->firstAttribute; + while (tAttr != RNIL) { + jam(); + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + if (aRec->tupleKey) { + buf[sz++] = aRec->attributeDescriptor; + buf[sz++] = (aRec->extPrecision >> 16); // charset number + } + tAttr = aRec->nextAttrInTable; + } + ndbrequire((int)sz == 2 * tabPtr.p->noOfPrimkey); + + LinearSectionPtr lsPtr[3]; + lsPtr[0].p = buf; + lsPtr[0].sz = sz; + // note: ACC does not reply + if (tabPtr.p->isTable() || tabPtr.p->isHashIndex()) + sendSignal(DBACC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1); + sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1); + return; + } + + ndbrequire(false); +} + +void +Dbdict::createTab_dihComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + //@todo check for master failed + + if(createTabPtr.p->m_errorCode == 0){ + jam(); + + CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr(); + conf->senderRef = reference(); + conf->senderData = createTabPtr.p->key; + sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF, + signal, CreateTabConf::SignalLength, JBB); + return; + } + + CreateTabRef * const ref = (CreateTabRef*)signal->getDataPtr(); + ref->senderRef = reference(); + ref->senderData = createTabPtr.p->key; + ref->errorCode = createTabPtr.p->m_errorCode; + ref->errorLine = 0; + ref->errorKey = 0; + ref->errorStatus = 0; + + sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_REF, + signal, CreateTabRef::SignalLength, JBB); +} + +void +Dbdict::createTab_commit(Signal * signal, CreateTabReq * req){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, req->senderData)); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + SchemaFile::TableEntry tabEntry; + tabEntry.m_tableVersion = tabPtr.p->tableVersion; + tabEntry.m_tableType = tabPtr.p->tableType; + tabEntry.m_tableState = SchemaFile::TABLE_ADD_COMMITTED; + tabEntry.m_gcp = tabPtr.p->gciTableCreated; + tabEntry.m_noOfPages = + DIV(tabPtr.p->packedSize + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS); + + Callback callback; + callback.m_callbackData = createTabPtr.p->key; + callback.m_callbackFunction = + safe_cast(&Dbdict::createTab_writeSchemaConf2); + + updateSchemaState(signal, tabPtr.i, &tabEntry, &callback); +} + +void +Dbdict::createTab_writeSchemaConf2(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + Callback c; + c.m_callbackData = callbackData; + c.m_callbackFunction = safe_cast(&Dbdict::createTab_alterComplete); + alterTab_activate(signal, createTabPtr, &c); +} + +void +Dbdict::createTab_alterComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + tabPtr.p->tabState = TableRecord::DEFINED; + + //@todo check error + //@todo check master failed + + CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr(); + conf->senderRef = reference(); + conf->senderData = createTabPtr.p->key; + sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF, + signal, CreateTabConf::SignalLength, JBB); + + if(createTabPtr.p->m_coordinatorRef != reference()){ + jam(); + c_opCreateTable.release(createTabPtr); + } +} + +void +Dbdict::createTab_drop(Signal* signal, CreateTabReq * req){ + jam(); + + const Uint32 key = req->senderData; + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, key)); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + tabPtr.p->tabState = TableRecord::DROPPING; + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.seize(dropTabPtr)); + + dropTabPtr.p->key = key; + c_opDropTable.add(dropTabPtr); + + dropTabPtr.p->m_errorCode = 0; + dropTabPtr.p->m_request.tableId = createTabPtr.p->m_tablePtrI; + dropTabPtr.p->m_requestType = DropTabReq::CreateTabDrop; + dropTabPtr.p->m_coordinatorRef = createTabPtr.p->m_coordinatorRef; + dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ; + + dropTabPtr.p->m_participantData.m_block = 0; + dropTabPtr.p->m_participantData.m_callback.m_callbackData = req->senderData; + dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = + safe_cast(&Dbdict::createTab_dropComplete); + dropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::createTab_dropComplete(Signal* signal, + Uint32 callbackData, + Uint32 returnCode){ + jam(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, callbackData)); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, callbackData)); + + TableRecordPtr tabPtr; + c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI); + + releaseTableObject(tabPtr.i); + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tabPtr.i); + tableEntry->m_tableState = SchemaFile::DROP_TABLE_COMMITTED; + + //@todo check error + //@todo check master failed + + CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr(); + conf->senderRef = reference(); + conf->senderData = createTabPtr.p->key; + sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF, + signal, CreateTabConf::SignalLength, JBB); + + if(createTabPtr.p->m_coordinatorRef != reference()){ + jam(); + c_opCreateTable.release(createTabPtr); + } + + c_opDropTable.release(dropTabPtr); +} + +void +Dbdict::alterTab_activate(Signal* signal, CreateTableRecordPtr createTabPtr, + Callback * c){ + + createTabPtr.p->m_callback = * c; + + signal->theData[0] = createTabPtr.p->key; + signal->theData[1] = reference(); + signal->theData[2] = createTabPtr.p->m_tablePtrI; + sendSignal(DBDIH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB); +} + +void +Dbdict::execTC_SCHVERCONF(Signal* signal){ + jamEntry(); + + CreateTableRecordPtr createTabPtr; + ndbrequire(c_opCreateTable.find(createTabPtr, signal->theData[1])); + + execute(signal, createTabPtr.p->m_callback, 0); +} + +#define tabRequire(cond, error) \ + if (!(cond)) { \ + jam(); \ + parseP->errorCode = error; parseP->errorLine = __LINE__; \ + parseP->errorKey = it.getKey(); \ + return; \ + }//if + +// handleAddTableFailure(signal, __LINE__, allocatedTable); + +void Dbdict::handleTabInfoInit(SimpleProperties::Reader & it, + ParseDictTabInfoRecord * parseP, + bool checkExist) +{ +/* ---------------------------------------------------------------- */ +// We always start by handling table name since this must be the first +// item in the list. Through the table name we can derive if it is a +// correct name, a new name or an already existing table. +/* ---------------------------------------------------------------- */ + + it.first(); + + SimpleProperties::UnpackStatus status; + DictTabInfo::Table tableDesc; tableDesc.init(); + status = SimpleProperties::unpack(it, &tableDesc, + DictTabInfo::TableMapping, + DictTabInfo::TableMappingSize, + true, true); + + if(status != SimpleProperties::Break){ + parseP->errorCode = CreateTableRef::InvalidFormat; + parseP->status = status; + parseP->errorKey = it.getKey(); + parseP->errorLine = __LINE__; + return; + } + + if(parseP->requestType == DictTabInfo::AlterTableFromAPI) + { + ndbrequire(!checkExist); + } + if(!checkExist) + { + ndbrequire(parseP->requestType == DictTabInfo::AlterTableFromAPI); + } + + /* ---------------------------------------------------------------- */ + // Verify that table name is an allowed table name. + // TODO + /* ---------------------------------------------------------------- */ + const Uint32 tableNameLength = strlen(tableDesc.TableName) + 1; + + TableRecord keyRecord; + tabRequire(tableNameLength <= sizeof(keyRecord.tableName), + CreateTableRef::TableNameTooLong); + strcpy(keyRecord.tableName, tableDesc.TableName); + + TableRecordPtr tablePtr; + c_tableRecordHash.find(tablePtr, keyRecord); + + if (checkExist){ + jam(); + /* ---------------------------------------------------------------- */ + // Check if table already existed. + /* ---------------------------------------------------------------- */ + tabRequire(tablePtr.i == RNIL, CreateTableRef::TableAlreadyExist); + } + + switch (parseP->requestType) { + case DictTabInfo::CreateTableFromAPI: { + jam(); + } + case DictTabInfo::AlterTableFromAPI:{ + jam(); + tablePtr.i = getFreeTableRecord(tableDesc.PrimaryTableId); + /* ---------------------------------------------------------------- */ + // Check if no free tables existed. + /* ---------------------------------------------------------------- */ + tabRequire(tablePtr.i != RNIL, CreateTableRef::NoMoreTableRecords); + + c_tableRecordPool.getPtr(tablePtr); + break; + } + case DictTabInfo::AddTableFromDict: + case DictTabInfo::ReadTableFromDiskSR: + case DictTabInfo::GetTabInfoConf: + { +/* ---------------------------------------------------------------- */ +// Get table id and check that table doesn't already exist +/* ---------------------------------------------------------------- */ + tablePtr.i = tableDesc.TableId; + + if (parseP->requestType == DictTabInfo::ReadTableFromDiskSR) { + ndbrequire(tablePtr.i == c_restartRecord.activeTable); + }//if + if (parseP->requestType == DictTabInfo::GetTabInfoConf) { + ndbrequire(tablePtr.i == c_restartRecord.activeTable); + }//if + + c_tableRecordPool.getPtr(tablePtr); + ndbrequire(tablePtr.p->tabState == TableRecord::NOT_DEFINED); + + //Uint32 oldTableVersion = tablePtr.p->tableVersion; + initialiseTableRecord(tablePtr); + if (parseP->requestType == DictTabInfo::AddTableFromDict) { + jam(); + tablePtr.p->tabState = TableRecord::DEFINING; + }//if +#ifdef HAVE_TABLE_REORG +/* ---------------------------------------------------------------- */ +// Get id of second table id and check that table doesn't already exist +// and set up links between first and second table. +/* ---------------------------------------------------------------- */ + TableRecordPtr secondTablePtr; + secondTablePtr.i = tableDesc.SecondTableId; + c_tableRecordPool.getPtr(secondTablePtr); + ndbrequire(secondTablePtr.p->tabState == TableRecord::NOT_DEFINED); + + initialiseTableRecord(secondTablePtr); + secondTablePtr.p->tabState = TableRecord::REORG_TABLE_PREPARED; + secondTablePtr.p->secondTable = tablePtr.i; + tablePtr.p->secondTable = secondTablePtr.i; +#endif +/* ---------------------------------------------------------------- */ +// Set table version +/* ---------------------------------------------------------------- */ + Uint32 tableVersion = tableDesc.TableVersion; + tablePtr.p->tableVersion = tableVersion; + + break; + } + default: + ndbrequire(false); + break; + }//switch + parseP->tablePtr = tablePtr; + + strcpy(tablePtr.p->tableName, keyRecord.tableName); + if (parseP->requestType != DictTabInfo::AlterTableFromAPI) { + jam(); +#ifdef VM_TRACE + ndbout_c("Dbdict: name=%s,id=%u", tablePtr.p->tableName, tablePtr.i); + TableRecordPtr tmp; + ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p)); +#endif + c_tableRecordHash.add(tablePtr); + } + + //tablePtr.p->noOfPrimkey = tableDesc.NoOfKeyAttr; + //tablePtr.p->noOfNullAttr = tableDesc.NoOfNullable; + //tablePtr.p->tupKeyLength = tableDesc.KeyLength; + tablePtr.p->noOfAttributes = tableDesc.NoOfAttributes; + tablePtr.p->storedTable = tableDesc.TableLoggedFlag; + tablePtr.p->minLoadFactor = tableDesc.MinLoadFactor; + tablePtr.p->maxLoadFactor = tableDesc.MaxLoadFactor; + tablePtr.p->fragmentType = (DictTabInfo::FragmentType)tableDesc.FragmentType; + tablePtr.p->tableType = (DictTabInfo::TableType)tableDesc.TableType; + tablePtr.p->kValue = tableDesc.TableKValue; + tablePtr.p->fragmentCount = tableDesc.FragmentCount; + + tablePtr.p->frmLen = tableDesc.FrmLen; + memcpy(tablePtr.p->frmData, tableDesc.FrmData, tableDesc.FrmLen); + + if(tableDesc.PrimaryTableId != RNIL) { + + tablePtr.p->primaryTableId = tableDesc.PrimaryTableId; + tablePtr.p->indexState = (TableRecord::IndexState)tableDesc.IndexState; + tablePtr.p->insertTriggerId = tableDesc.InsertTriggerId; + tablePtr.p->updateTriggerId = tableDesc.UpdateTriggerId; + tablePtr.p->deleteTriggerId = tableDesc.DeleteTriggerId; + tablePtr.p->customTriggerId = tableDesc.CustomTriggerId; + } else { + tablePtr.p->primaryTableId = RNIL; + tablePtr.p->indexState = TableRecord::IS_UNDEFINED; + tablePtr.p->insertTriggerId = RNIL; + tablePtr.p->updateTriggerId = RNIL; + tablePtr.p->deleteTriggerId = RNIL; + tablePtr.p->customTriggerId = RNIL; + } + tablePtr.p->buildTriggerId = RNIL; + tablePtr.p->indexLocal = 0; + + handleTabInfo(it, parseP); + + if(parseP->errorCode != 0) + { + /** + * Release table + */ + releaseTableObject(tablePtr.i, checkExist); + } +}//handleTabInfoInit() + +void Dbdict::handleTabInfo(SimpleProperties::Reader & it, + ParseDictTabInfoRecord * parseP) +{ + TableRecordPtr tablePtr = parseP->tablePtr; + + SimpleProperties::UnpackStatus status; + + Uint32 keyCount = 0; + Uint32 keyLength = 0; + Uint32 attrCount = tablePtr.p->noOfAttributes; + Uint32 nullCount = 0; + Uint32 nullBits = 0; + Uint32 noOfCharsets = 0; + Uint16 charsets[128]; + Uint32 recordLength = 0; + AttributeRecordPtr attrPtr; + c_attributeRecordHash.removeAll(); + + for(Uint32 i = 0; i<attrCount; i++){ + /** + * Attribute Name + */ + DictTabInfo::Attribute attrDesc; attrDesc.init(); + status = SimpleProperties::unpack(it, &attrDesc, + DictTabInfo::AttributeMapping, + DictTabInfo::AttributeMappingSize, + true, true); + if(status != SimpleProperties::Break){ + parseP->errorCode = CreateTableRef::InvalidFormat; + parseP->status = status; + parseP->errorKey = it.getKey(); + parseP->errorLine = __LINE__; + return; + } + + /** + * Check that attribute is not defined twice + */ + AttributeRecord tmpAttr; + { + strcpy(tmpAttr.attributeName, attrDesc.AttributeName); + + AttributeRecordPtr attrPtr; + c_attributeRecordHash.find(attrPtr, tmpAttr); + + if(attrPtr.i != RNIL){ + parseP->errorCode = CreateTableRef::AttributeNameTwice; + return; + } + } + + if(!getNewAttributeRecord(tablePtr, attrPtr)){ + jam(); + parseP->errorCode = CreateTableRef::NoMoreAttributeRecords; + return; + } + + /** + * TmpAttrib to Attribute mapping + */ + strcpy(attrPtr.p->attributeName, attrDesc.AttributeName); + attrPtr.p->attributeId = attrDesc.AttributeId; + attrPtr.p->tupleKey = (keyCount + 1) * attrDesc.AttributeKeyFlag; + + attrPtr.p->extPrecision = attrDesc.AttributeExtPrecision; + attrPtr.p->extScale = attrDesc.AttributeExtScale; + attrPtr.p->extLength = attrDesc.AttributeExtLength; + // charset in upper half of precision + unsigned csNumber = (attrPtr.p->extPrecision >> 16); + if (csNumber != 0) { + /* + * A new charset is first accessed here on this node. + * TODO use separate thread (e.g. via NDBFS) if need to load from file + */ + CHARSET_INFO* cs = get_charset(csNumber, MYF(0)); + if (cs == NULL) { + parseP->errorCode = CreateTableRef::InvalidCharset; + parseP->errorLine = __LINE__; + return; + } + // XXX should be done somewhere in mysql + all_charsets[cs->number] = cs; + unsigned i = 0; + while (i < noOfCharsets) { + if (charsets[i] == csNumber) + break; + i++; + } + if (i == noOfCharsets) { + noOfCharsets++; + if (noOfCharsets > sizeof(charsets)/sizeof(charsets[0])) { + parseP->errorCode = CreateTableRef::InvalidFormat; + parseP->errorLine = __LINE__; + return; + } + charsets[i] = csNumber; + } + } + + // compute attribute size and array size + bool translateOk = attrDesc.translateExtType(); + tabRequire(translateOk, CreateTableRef::Inconsistency); + + if(attrDesc.AttributeArraySize > 65535){ + parseP->errorCode = CreateTableRef::ArraySizeTooBig; + parseP->status = status; + parseP->errorKey = it.getKey(); + parseP->errorLine = __LINE__; + return; + } + + Uint32 desc = 0; + AttributeDescriptor::setType(desc, attrDesc.AttributeExtType); + AttributeDescriptor::setSize(desc, attrDesc.AttributeSize); + AttributeDescriptor::setArray(desc, attrDesc.AttributeArraySize); + AttributeDescriptor::setNullable(desc, attrDesc.AttributeNullableFlag); + AttributeDescriptor::setDKey(desc, attrDesc.AttributeDKey); + AttributeDescriptor::setPrimaryKey(desc, attrDesc.AttributeKeyFlag); + attrPtr.p->attributeDescriptor = desc; + attrPtr.p->autoIncrement = attrDesc.AttributeAutoIncrement; + strcpy(attrPtr.p->defaultValue, attrDesc.AttributeDefaultValue); + + tabRequire(attrDesc.AttributeId == i, CreateTableRef::InvalidFormat); + + attrCount ++; + keyCount += attrDesc.AttributeKeyFlag; + nullCount += attrDesc.AttributeNullableFlag; + + const Uint32 aSz = (1 << attrDesc.AttributeSize); + Uint32 sz; + if(aSz != 1) + { + sz = ((aSz * attrDesc.AttributeArraySize) + 31) >> 5; + } + else + { + sz = 0; + nullBits += attrDesc.AttributeArraySize; + } + + if(attrDesc.AttributeArraySize == 0) + { + parseP->errorCode = CreateTableRef::InvalidArraySize; + parseP->status = status; + parseP->errorKey = it.getKey(); + parseP->errorLine = __LINE__; + return; + } + + recordLength += sz; + if(attrDesc.AttributeKeyFlag){ + keyLength += sz; + + if(attrDesc.AttributeNullableFlag){ + parseP->errorCode = CreateTableRef::NullablePrimaryKey; + parseP->status = status; + parseP->errorKey = it.getKey(); + parseP->errorLine = __LINE__; + return; + } + } + + if (parseP->requestType != DictTabInfo::AlterTableFromAPI) + c_attributeRecordHash.add(attrPtr); + + if(!it.next()) + break; + + if(it.getKey() != DictTabInfo::AttributeName) + break; + }//while + + tablePtr.p->noOfPrimkey = keyCount; + tablePtr.p->noOfNullAttr = nullCount; + tablePtr.p->noOfCharsets = noOfCharsets; + tablePtr.p->tupKeyLength = keyLength; + tablePtr.p->noOfNullBits = nullCount + nullBits; + + tabRequire(recordLength<= MAX_TUPLE_SIZE_IN_WORDS, + CreateTableRef::RecordTooBig); + tabRequire(keyLength <= MAX_KEY_SIZE_IN_WORDS, + CreateTableRef::InvalidPrimaryKeySize); + tabRequire(keyLength > 0, + CreateTableRef::InvalidPrimaryKeySize); + +}//handleTabInfo() + + +/* ---------------------------------------------------------------- */ +// DICTTABCONF is sent when participants have received all DICTTABINFO +// and successfully handled it. +// Also sent to self (DICT master) when index table creation ready. +/* ---------------------------------------------------------------- */ +void Dbdict::execCREATE_TABLE_CONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + + CreateTableConf * const conf = (CreateTableConf *)signal->getDataPtr(); + // assume part of create index operation + OpCreateIndexPtr opPtr; + c_opCreateIndex.find(opPtr, conf->senderData); + ndbrequire(! opPtr.isNull()); + opPtr.p->m_request.setIndexId(conf->tableId); + opPtr.p->m_request.setIndexVersion(conf->tableVersion); + createIndex_fromCreateTable(signal, opPtr); +}//execCREATE_TABLE_CONF() + +void Dbdict::execCREATE_TABLE_REF(Signal* signal) +{ + jamEntry(); + + CreateTableRef * const ref = (CreateTableRef *)signal->getDataPtr(); + // assume part of create index operation + OpCreateIndexPtr opPtr; + c_opCreateIndex.find(opPtr, ref->senderData); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + createIndex_fromCreateTable(signal, opPtr); +}//execCREATE_TABLE_REF() + +/* ---------------------------------------------------------------- */ +// New global checkpoint created. +/* ---------------------------------------------------------------- */ +void Dbdict::execWAIT_GCP_CONF(Signal* signal) +{ +#if 0 + TableRecordPtr tablePtr; + jamEntry(); + WaitGCPConf* const conf = (WaitGCPConf*)&signal->theData[0]; + c_tableRecordPool.getPtr(tablePtr, c_connRecord.connTableId); + tablePtr.p->gciTableCreated = conf->gcp; + sendUpdateSchemaState(signal, + tablePtr.i, + SchemaFile::TABLE_ADD_COMMITTED, + c_connRecord.noOfPagesForTable, + conf->gcp); +#endif +}//execWAIT_GCP_CONF() + +/* ---------------------------------------------------------------- */ +// Refused new global checkpoint. +/* ---------------------------------------------------------------- */ +void Dbdict::execWAIT_GCP_REF(Signal* signal) +{ + jamEntry(); + WaitGCPRef* const ref = (WaitGCPRef*)&signal->theData[0]; +/* ---------------------------------------------------------------- */ +// Error Handling code needed +/* ---------------------------------------------------------------- */ + progError(ref->errorCode, 0); +}//execWAIT_GCP_REF() + + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: DROP TABLE -------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code used to drop a table. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ +void +Dbdict::execDROP_TABLE_REQ(Signal* signal){ + jamEntry(); + DropTableReq* req = (DropTableReq*)signal->getDataPtr(); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, req->tableId, false); + if(tablePtr.isNull()){ + jam(); + dropTableRef(signal, req, DropTableRef::NoSuchTable); + return; + } + + if(getOwnNodeId() != c_masterNodeId){ + jam(); + dropTableRef(signal, req, DropTableRef::NotMaster); + return; + } + + if(c_blockState != BS_IDLE){ + jam(); + dropTableRef(signal, req, DropTableRef::Busy); + return; + } + + const TableRecord::TabState tabState = tablePtr.p->tabState; + bool ok = false; + switch(tabState){ + case TableRecord::NOT_DEFINED: + case TableRecord::REORG_TABLE_PREPARED: + case TableRecord::DEFINING: + case TableRecord::CHECKED: + jam(); + dropTableRef(signal, req, DropTableRef::NoSuchTable); + return; + case TableRecord::DEFINED: + ok = true; + jam(); + break; + case TableRecord::PREPARE_DROPPING: + case TableRecord::DROPPING: + jam(); + dropTableRef(signal, req, DropTableRef::DropInProgress); + return; + } + ndbrequire(ok); + + if(tablePtr.p->tableVersion != req->tableVersion){ + jam(); + dropTableRef(signal, req, DropTableRef::InvalidTableVersion); + return; + } + + /** + * Seems ok + */ + DropTableRecordPtr dropTabPtr; + c_opDropTable.seize(dropTabPtr); + + if(dropTabPtr.isNull()){ + jam(); + dropTableRef(signal, req, DropTableRef::NoDropTableRecordAvailable); + return; + } + + c_blockState = BS_BUSY; + + dropTabPtr.p->key = ++c_opRecordSequence; + c_opDropTable.add(dropTabPtr); + + tablePtr.p->tabState = TableRecord::PREPARE_DROPPING; + + dropTabPtr.p->m_request = * req; + dropTabPtr.p->m_errorCode = 0; + dropTabPtr.p->m_requestType = DropTabReq::OnlineDropTab; + dropTabPtr.p->m_coordinatorRef = reference(); + dropTabPtr.p->m_coordinatorData.m_gsn = GSN_PREP_DROP_TAB_REQ; + dropTabPtr.p->m_coordinatorData.m_block = 0; + prepDropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::dropTableRef(Signal * signal, + DropTableReq * req, DropTableRef::ErrorCode errCode){ + + Uint32 tableId = req->tableId; + Uint32 tabVersion = req->tableVersion; + Uint32 senderData = req->senderData; + Uint32 senderRef = req->senderRef; + + DropTableRef * ref = (DropTableRef*)signal->getDataPtrSend(); + ref->tableId = tableId; + ref->tableVersion = tabVersion; + ref->senderData = senderData; + ref->senderRef = reference(); + ref->errorCode = errCode; + ref->masterNodeId = c_masterNodeId; + sendSignal(senderRef, GSN_DROP_TABLE_REF, signal, + DropTableRef::SignalLength, JBB); +} + +void +Dbdict::prepDropTab_nextStep(Signal* signal, DropTableRecordPtr dropTabPtr){ + + /** + * No errors currently allowed + */ + ndbrequire(dropTabPtr.p->m_errorCode == 0); + + Uint32 block = 0; + switch(dropTabPtr.p->m_coordinatorData.m_block){ + case 0: + jam(); + block = dropTabPtr.p->m_coordinatorData.m_block = DBDICT; + break; + case DBDICT: + jam(); + block = dropTabPtr.p->m_coordinatorData.m_block = DBLQH; + break; + case DBLQH: + jam(); + block = dropTabPtr.p->m_coordinatorData.m_block = DBTC; + break; + case DBTC: + jam(); + block = dropTabPtr.p->m_coordinatorData.m_block = DBDIH; + break; + case DBDIH: + jam(); + prepDropTab_complete(signal, dropTabPtr); + return; + default: + ndbrequire(false); + } + + PrepDropTabReq * prep = (PrepDropTabReq*)signal->getDataPtrSend(); + prep->senderRef = reference(); + prep->senderData = dropTabPtr.p->key; + prep->tableId = dropTabPtr.p->m_request.tableId; + prep->requestType = dropTabPtr.p->m_requestType; + + dropTabPtr.p->m_coordinatorData.m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(block, c_aliveNodes); + sendSignal(rg, GSN_PREP_DROP_TAB_REQ, signal, + PrepDropTabReq::SignalLength, JBB); + +#if 0 + for (Uint32 i = 1; i < MAX_NDB_NODES; i++){ + if(c_aliveNodes.get(i)){ + jam(); + BlockReference ref = numberToRef(block, i); + + dropTabPtr.p->m_coordinatorData.m_signalCounter.setWaitingFor(i); + } + } +#endif +} + +void +Dbdict::execPREP_DROP_TAB_CONF(Signal * signal){ + jamEntry(); + + PrepDropTabConf * prep = (PrepDropTabConf*)signal->getDataPtr(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData)); + + ndbrequire(dropTabPtr.p->m_coordinatorRef == reference()); + ndbrequire(dropTabPtr.p->m_request.tableId == prep->tableId); + ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_PREP_DROP_TAB_REQ); + + Uint32 nodeId = refToNode(prep->senderRef); + dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId); + + if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){ + jam(); + return; + } + prepDropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::execPREP_DROP_TAB_REF(Signal* signal){ + jamEntry(); + + PrepDropTabRef * prep = (PrepDropTabRef*)signal->getDataPtr(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData)); + + ndbrequire(dropTabPtr.p->m_coordinatorRef == reference()); + ndbrequire(dropTabPtr.p->m_request.tableId == prep->tableId); + ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_PREP_DROP_TAB_REQ); + + Uint32 nodeId = refToNode(prep->senderRef); + dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId); + + Uint32 block = refToBlock(prep->senderRef); + if((prep->errorCode == PrepDropTabRef::NoSuchTable && block == DBLQH) || + (prep->errorCode == PrepDropTabRef::NF_FakeErrorREF)){ + jam(); + /** + * Ignore errors: + * 1) no such table and LQH, it might not exists in different LQH's + * 2) node failure... + */ + } else { + dropTabPtr.p->setErrorCode((Uint32)prep->errorCode); + } + + if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){ + jam(); + return; + } + prepDropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::prepDropTab_complete(Signal* signal, DropTableRecordPtr dropTabPtr){ + jam(); + + dropTabPtr.p->m_coordinatorData.m_gsn = GSN_DROP_TAB_REQ; + dropTabPtr.p->m_coordinatorData.m_block = DBDICT; + + DropTabReq * req = (DropTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = dropTabPtr.p->key; + req->tableId = dropTabPtr.p->m_request.tableId; + req->requestType = dropTabPtr.p->m_requestType; + + dropTabPtr.p->m_coordinatorData.m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_DROP_TAB_REQ, signal, + DropTabReq::SignalLength, JBB); +} + +void +Dbdict::execDROP_TAB_REF(Signal* signal){ + jamEntry(); + + DropTabRef * const req = (DropTabRef*)signal->getDataPtr(); + + Uint32 block = refToBlock(req->senderRef); + ndbrequire(req->errorCode == DropTabRef::NF_FakeErrorREF || + (req->errorCode == DropTabRef::NoSuchTable && + (block == DBTUP || block == DBACC || block == DBLQH))); + + if(block != DBDICT){ + jam(); + ndbrequire(refToNode(req->senderRef) == getOwnNodeId()); + dropTab_localDROP_TAB_CONF(signal); + return; + } + ndbrequire(false); +} + +void +Dbdict::execDROP_TAB_CONF(Signal* signal){ + jamEntry(); + + DropTabConf * const req = (DropTabConf*)signal->getDataPtr(); + + if(refToBlock(req->senderRef) != DBDICT){ + jam(); + ndbrequire(refToNode(req->senderRef) == getOwnNodeId()); + dropTab_localDROP_TAB_CONF(signal); + return; + } + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, req->senderData)); + + ndbrequire(dropTabPtr.p->m_coordinatorRef == reference()); + ndbrequire(dropTabPtr.p->m_request.tableId == req->tableId); + ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_DROP_TAB_REQ); + + Uint32 nodeId = refToNode(req->senderRef); + dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId); + + if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){ + jam(); + return; + } + + DropTableConf* conf = (DropTableConf*)signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = dropTabPtr.p->m_request.senderData; + conf->tableId = dropTabPtr.p->m_request.tableId; + conf->tableVersion = dropTabPtr.p->m_request.tableVersion; + + Uint32 ref = dropTabPtr.p->m_request.senderRef; + sendSignal(ref, GSN_DROP_TABLE_CONF, signal, + DropTableConf::SignalLength, JBB); + + c_opDropTable.release(dropTabPtr); + c_blockState = BS_IDLE; +} + +/** + * DROP TABLE PARTICIPANT CODE + */ +void +Dbdict::execPREP_DROP_TAB_REQ(Signal* signal){ + jamEntry(); + PrepDropTabReq * prep = (PrepDropTabReq*)signal->getDataPtrSend(); + + DropTableRecordPtr dropTabPtr; + if(prep->senderRef == reference()){ + jam(); + ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData)); + ndbrequire(dropTabPtr.p->m_requestType == prep->requestType); + } else { + jam(); + c_opDropTable.seize(dropTabPtr); + if(!dropTabPtr.isNull()){ + dropTabPtr.p->key = prep->senderData; + c_opDropTable.add(dropTabPtr); + } + } + + ndbrequire(!dropTabPtr.isNull()); + + dropTabPtr.p->m_errorCode = 0; + dropTabPtr.p->m_request.tableId = prep->tableId; + dropTabPtr.p->m_requestType = prep->requestType; + dropTabPtr.p->m_coordinatorRef = prep->senderRef; + dropTabPtr.p->m_participantData.m_gsn = GSN_PREP_DROP_TAB_REQ; + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, prep->tableId); + tablePtr.p->tabState = TableRecord::PREPARE_DROPPING; + + /** + * Modify schema + */ + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tablePtr.i); + SchemaFile::TableState tabState = + (SchemaFile::TableState)tableEntry->m_tableState; + ndbrequire(tabState == SchemaFile::TABLE_ADD_COMMITTED || + tabState == SchemaFile::ALTER_TABLE_COMMITTED); + tableEntry->m_tableState = SchemaFile::DROP_TABLE_STARTED; + computeChecksum((SchemaFile*)pagePtr.p); + + ndbrequire(c_writeSchemaRecord.inUse == false); + c_writeSchemaRecord.inUse = true; + + c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage; + c_writeSchemaRecord.m_callback.m_callbackData = dropTabPtr.p->key; + c_writeSchemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::prepDropTab_writeSchemaConf); + startWriteSchemaFile(signal); +} + +void +Dbdict::prepDropTab_writeSchemaConf(Signal* signal, + Uint32 dropTabPtrI, + Uint32 returnCode){ + jam(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI)); + + ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_PREP_DROP_TAB_REQ); + + /** + * There probably should be node fail handlign here + * + * To check that coordinator hasn't died + */ + + PrepDropTabConf * prep = (PrepDropTabConf*)signal->getDataPtr(); + prep->senderRef = reference(); + prep->senderData = dropTabPtrI; + prep->tableId = dropTabPtr.p->m_request.tableId; + + dropTabPtr.p->m_participantData.m_gsn = GSN_PREP_DROP_TAB_CONF; + sendSignal(dropTabPtr.p->m_coordinatorRef, GSN_PREP_DROP_TAB_CONF, signal, + PrepDropTabConf::SignalLength, JBB); +} + +void +Dbdict::execDROP_TAB_REQ(Signal* signal){ + jamEntry(); + DropTabReq * req = (DropTabReq*)signal->getDataPtrSend(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, req->senderData)); + + ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_PREP_DROP_TAB_CONF); + dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ; + + ndbrequire(dropTabPtr.p->m_requestType == req->requestType); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, dropTabPtr.p->m_request.tableId); + tablePtr.p->tabState = TableRecord::DROPPING; + + dropTabPtr.p->m_participantData.m_block = 0; + dropTabPtr.p->m_participantData.m_callback.m_callbackData = dropTabPtr.p->key; + dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = + safe_cast(&Dbdict::dropTab_complete); + dropTab_nextStep(signal, dropTabPtr); +} + +#include <DebuggerNames.hpp> + +void +Dbdict::dropTab_nextStep(Signal* signal, DropTableRecordPtr dropTabPtr){ + + /** + * No errors currently allowed + */ + ndbrequire(dropTabPtr.p->m_errorCode == 0); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, dropTabPtr.p->m_request.tableId); + + Uint32 block = 0; + switch(dropTabPtr.p->m_participantData.m_block){ + case 0: + jam(); + block = DBTC; + break; + case DBTC: + jam(); + if (tablePtr.p->isTable() || tablePtr.p->isHashIndex()) + block = DBACC; + if (tablePtr.p->isOrderedIndex()) + block = DBTUP; + break; + case DBACC: + jam(); + block = DBTUP; + break; + case DBTUP: + jam(); + if (tablePtr.p->isTable() || tablePtr.p->isHashIndex()) + block = DBLQH; + if (tablePtr.p->isOrderedIndex()) + block = DBTUX; + break; + case DBTUX: + jam(); + block = DBLQH; + break; + case DBLQH: + jam(); + block = DBDIH; + break; + case DBDIH: + jam(); + execute(signal, dropTabPtr.p->m_participantData.m_callback, 0); + return; + } + ndbrequire(block != 0); + dropTabPtr.p->m_participantData.m_block = block; + + DropTabReq * req = (DropTabReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = dropTabPtr.p->key; + req->tableId = dropTabPtr.p->m_request.tableId; + req->requestType = dropTabPtr.p->m_requestType; + + const Uint32 nodeId = getOwnNodeId(); + dropTabPtr.p->m_participantData.m_signalCounter.clearWaitingFor(); + dropTabPtr.p->m_participantData.m_signalCounter.setWaitingFor(nodeId); + BlockReference ref = numberToRef(block, 0); + sendSignal(ref, GSN_DROP_TAB_REQ, signal, DropTabReq::SignalLength, JBB); +} + +void +Dbdict::dropTab_localDROP_TAB_CONF(Signal* signal){ + jamEntry(); + + DropTabConf * conf = (DropTabConf*)signal->getDataPtr(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, conf->senderData)); + + ndbrequire(dropTabPtr.p->m_request.tableId == conf->tableId); + ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_DROP_TAB_REQ); + + Uint32 nodeId = refToNode(conf->senderRef); + dropTabPtr.p->m_participantData.m_signalCounter.clearWaitingFor(nodeId); + + if(!dropTabPtr.p->m_participantData.m_signalCounter.done()){ + jam(); + ndbrequire(false); + return; + } + dropTab_nextStep(signal, dropTabPtr); +} + +void +Dbdict::dropTab_complete(Signal* signal, + Uint32 dropTabPtrI, + Uint32 returnCode){ + jam(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI)); + + Uint32 tableId = dropTabPtr.p->m_request.tableId; + + /** + * Write to schema file + */ + PageRecordPtr pagePtr; + c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage); + + SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tableId); + SchemaFile::TableState tabState = + (SchemaFile::TableState)tableEntry->m_tableState; + ndbrequire(tabState == SchemaFile::DROP_TABLE_STARTED); + tableEntry->m_tableState = SchemaFile::DROP_TABLE_COMMITTED; + computeChecksum((SchemaFile*)pagePtr.p); + + ndbrequire(c_writeSchemaRecord.inUse == false); + c_writeSchemaRecord.inUse = true; + + c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage; + c_writeSchemaRecord.m_callback.m_callbackData = dropTabPtr.p->key; + c_writeSchemaRecord.m_callback.m_callbackFunction = + safe_cast(&Dbdict::dropTab_writeSchemaConf); + startWriteSchemaFile(signal); +} + +void +Dbdict::dropTab_writeSchemaConf(Signal* signal, + Uint32 dropTabPtrI, + Uint32 returnCode){ + jam(); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI)); + + ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_DROP_TAB_REQ); + + dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_CONF; + + releaseTableObject(dropTabPtr.p->m_request.tableId); + + DropTabConf * conf = (DropTabConf*)signal->getDataPtr(); + conf->senderRef = reference(); + conf->senderData = dropTabPtrI; + conf->tableId = dropTabPtr.p->m_request.tableId; + + dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_CONF; + sendSignal(dropTabPtr.p->m_coordinatorRef, GSN_DROP_TAB_CONF, signal, + DropTabConf::SignalLength, JBB); + + if(dropTabPtr.p->m_coordinatorRef != reference()){ + c_opDropTable.release(dropTabPtr); + } +} + +void Dbdict::releaseTableObject(Uint32 tableId, bool removeFromHash) +{ + TableRecordPtr tablePtr; + AttributeRecordPtr attrPtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + if (removeFromHash) + { +#ifdef VM_TRACE + TableRecordPtr tmp; + ndbrequire(c_tableRecordHash.find(tmp, * tablePtr.p)); +#endif + c_tableRecordHash.remove(tablePtr); + } + tablePtr.p->tabState = TableRecord::NOT_DEFINED; + + Uint32 nextAttrRecord = tablePtr.p->firstAttribute; + while (nextAttrRecord != RNIL) { + jam(); +/* ---------------------------------------------------------------- */ +// Release all attribute records +/* ---------------------------------------------------------------- */ + c_attributeRecordPool.getPtr(attrPtr, nextAttrRecord); + nextAttrRecord = attrPtr.p->nextAttrInTable; + c_attributeRecordPool.release(attrPtr); + }//if +#ifdef HAVE_TABLE_REORG + Uint32 secondTableId = tablePtr.p->secondTable; + initialiseTableRecord(tablePtr); + c_tableRecordPool.getPtr(tablePtr, secondTableId); + initialiseTableRecord(tablePtr); +#endif + return; +}//releaseTableObject() + +/** + * DICT receives these on index create and drop. + */ +void Dbdict::execDROP_TABLE_CONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + + DropTableConf * const conf = (DropTableConf *)signal->getDataPtr(); + // assume part of drop index operation + OpDropIndexPtr opPtr; + c_opDropIndex.find(opPtr, conf->senderData); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_request.getIndexId() == conf->tableId); + ndbrequire(opPtr.p->m_request.getIndexVersion() == conf->tableVersion); + dropIndex_fromDropTable(signal, opPtr); +} + +void Dbdict::execDROP_TABLE_REF(Signal* signal) +{ + jamEntry(); + + DropTableRef * const ref = (DropTableRef *)signal->getDataPtr(); + // assume part of drop index operation + OpDropIndexPtr opPtr; + c_opDropIndex.find(opPtr, ref->senderData); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + opPtr.p->m_errorLine = __LINE__; + dropIndex_fromDropTable(signal, opPtr); +} + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: EXTERNAL INTERFACE TO DATA -------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* This module contains the code that is used by other modules to. */ +/* access the data within DBDICT. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +void Dbdict::execGET_TABLEDID_REQ(Signal * signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 1); + GetTableIdReq const * req = (GetTableIdReq *)signal->getDataPtr(); + Uint32 senderData = req->senderData; + Uint32 senderRef = req->senderRef; + Uint32 len = req->len; + + if(len>MAX_TAB_NAME_SIZE) + { + jam(); + sendGET_TABLEID_REF((Signal*)signal, + (GetTableIdReq *)req, + GetTableIdRef::TableNameTooLong); + return; + } + + char tableName[MAX_TAB_NAME_SIZE]; + TableRecord keyRecord; + SegmentedSectionPtr ssPtr; + signal->getSection(ssPtr,GetTableIdReq::TABLE_NAME); + copy((Uint32*)tableName, ssPtr); + strcpy(keyRecord.tableName, tableName); + releaseSections(signal); + + if(len > sizeof(keyRecord.tableName)){ + jam(); + sendGET_TABLEID_REF((Signal*)signal, + (GetTableIdReq *)req, + GetTableIdRef::TableNameTooLong); + return; + } + + TableRecordPtr tablePtr; + if(!c_tableRecordHash.find(tablePtr, keyRecord)) { + jam(); + sendGET_TABLEID_REF((Signal*)signal, + (GetTableIdReq *)req, + GetTableIdRef::TableNotDefined); + return; + } + GetTableIdConf * conf = (GetTableIdConf *)req; + conf->tableId = tablePtr.p->tableId; + conf->schemaVersion = tablePtr.p->tableVersion; + conf->senderData = senderData; + sendSignal(senderRef, GSN_GET_TABLEID_CONF, signal, + GetTableIdConf::SignalLength, JBB); + +} + + +void Dbdict::sendGET_TABLEID_REF(Signal* signal, + GetTableIdReq * req, + GetTableIdRef::ErrorCode errorCode) +{ + GetTableIdRef * const ref = (GetTableIdRef *)req; + /** + * The format of GetTabInfo Req/Ref is the same + */ + BlockReference retRef = req->senderRef; + ref->err = errorCode; + sendSignal(retRef, GSN_GET_TABLEID_REF, signal, + GetTableIdRef::SignalLength, JBB); +}//sendGET_TABINFOREF() + +/* ---------------------------------------------------------------- */ +// Get a full table description. +/* ---------------------------------------------------------------- */ +void Dbdict::execGET_TABINFOREQ(Signal* signal) +{ + jamEntry(); + if(!assembleFragments(signal)) + { + return; + } + + GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0]; + + /** + * If I get a GET_TABINFO_REQ from myself + * it's is a one from the time queue + */ + bool fromTimeQueue = (signal->senderBlockRef() == reference()); + + if (c_retrieveRecord.busyState && fromTimeQueue == true) { + jam(); + + sendSignalWithDelay(reference(), GSN_GET_TABINFOREQ, signal, 30, + signal->length()); + return; + }//if + + const Uint32 MAX_WAITERS = 5; + + if(c_retrieveRecord.busyState && fromTimeQueue == false){ + jam(); + if(c_retrieveRecord.noOfWaiters < MAX_WAITERS){ + jam(); + c_retrieveRecord.noOfWaiters++; + + sendSignalWithDelay(reference(), GSN_GET_TABINFOREQ, signal, 30, + signal->length()); + return; + } + + sendGET_TABINFOREF(signal, req, GetTabInfoRef::Busy); + return; + } + + if(fromTimeQueue){ + jam(); + c_retrieveRecord.noOfWaiters--; + } + + const bool useLongSig = (req->requestType & GetTabInfoReq::LongSignalConf); + const Uint32 reqType = req->requestType & (~GetTabInfoReq::LongSignalConf); + + TableRecordPtr tablePtr; + if(reqType == GetTabInfoReq::RequestByName){ + jam(); + ndbrequire(signal->getNoOfSections() == 1); + const Uint32 len = req->tableNameLen; + + TableRecord keyRecord; + if(len > sizeof(keyRecord.tableName)){ + jam(); + releaseSections(signal); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNameTooLong); + return; + } + + char tableName[MAX_TAB_NAME_SIZE]; + SegmentedSectionPtr ssPtr; + signal->getSection(ssPtr,GetTabInfoReq::TABLE_NAME); + SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); + r0.reset(); // undo implicit first() + if(r0.getWords((Uint32*)tableName, ((len + 3)/4))) + memcpy(keyRecord.tableName, tableName, len); + else { + jam(); + releaseSections(signal); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); + return; + } + releaseSections(signal); + // memcpy(keyRecord.tableName, req->tableName, len); + //ntohS(&keyRecord.tableName[0], len); + + c_tableRecordHash.find(tablePtr, keyRecord); + } else { + jam(); + c_tableRecordPool.getPtr(tablePtr, req->tableId, false); + } + + // The table seached for was not found + if(tablePtr.i == RNIL){ + jam(); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::InvalidTableId); + return; + }//if + + if (tablePtr.p->tabState != TableRecord::DEFINED) { + jam(); + sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); + return; + }//if + + c_retrieveRecord.busyState = true; + c_retrieveRecord.blockRef = req->senderRef; + c_retrieveRecord.m_senderData = req->senderData; + c_retrieveRecord.tableId = tablePtr.i; + c_retrieveRecord.currentSent = 0; + c_retrieveRecord.m_useLongSig = useLongSig; + + c_packTable.m_state = PackTable::PTS_GET_TAB; + + signal->theData[0] = ZPACK_TABLE_INTO_PAGES; + signal->theData[1] = tablePtr.i; + signal->theData[2] = c_retrieveRecord.retrievePage; + sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB); +}//execGET_TABINFOREQ() + +void Dbdict::sendGetTabResponse(Signal* signal) +{ + PageRecordPtr pagePtr; + DictTabInfo * const conf = (DictTabInfo *)&signal->theData[0]; + conf->senderRef = reference(); + conf->senderData = c_retrieveRecord.m_senderData; + conf->requestType = DictTabInfo::GetTabInfoConf; + conf->totalLen = c_retrieveRecord.retrievedNoOfWords; + + c_pageRecordArray.getPtr(pagePtr, c_retrieveRecord.retrievePage); + Uint32* pagePointer = (Uint32*)&pagePtr.p->word[0] + ZPAGE_HEADER_SIZE; + + if(c_retrieveRecord.m_useLongSig){ + jam(); + GetTabInfoConf* conf = (GetTabInfoConf*)signal->getDataPtr(); + conf->gci = 0; + conf->tableId = c_retrieveRecord.tableId; + conf->senderData = c_retrieveRecord.m_senderData; + conf->totalLen = c_retrieveRecord.retrievedNoOfWords; + + Callback c = { safe_cast(&Dbdict::initRetrieveRecord), 0 }; + LinearSectionPtr ptr[3]; + ptr[0].p = pagePointer; + ptr[0].sz = c_retrieveRecord.retrievedNoOfWords; + sendFragmentedSignal(c_retrieveRecord.blockRef, + GSN_GET_TABINFO_CONF, + signal, + GetTabInfoConf::SignalLength, + JBB, + ptr, + 1, + c); + return; + } + + ndbrequire(false); +}//sendGetTabResponse() + +void Dbdict::sendGET_TABINFOREF(Signal* signal, + GetTabInfoReq * req, + GetTabInfoRef::ErrorCode errorCode) +{ + jamEntry(); + GetTabInfoRef * const ref = (GetTabInfoRef *)&signal->theData[0]; + /** + * The format of GetTabInfo Req/Ref is the same + */ + BlockReference retRef = req->senderRef; + ref->errorCode = errorCode; + + sendSignal(retRef, GSN_GET_TABINFOREF, signal, signal->length(), JBB); +}//sendGET_TABINFOREF() + +Uint32 convertEndian(Uint32 in) { +#ifdef WORDS_BIGENDIAN + Uint32 ut = 0; + ut += ((in >> 24) & 255); + ut += (((in >> 16) & 255) << 8); + ut += (((in >> 8) & 255) << 16); + ut += ((in & 255) << 24); + return ut; +#else + return in; +#endif +} +void +Dbdict::execLIST_TABLES_REQ(Signal* signal) +{ + jamEntry(); + Uint32 i; + ListTablesReq * req = (ListTablesReq*)signal->getDataPtr(); + Uint32 senderRef = req->senderRef; + Uint32 senderData = req->senderData; + // save req flags + const Uint32 reqTableId = req->getTableId(); + const Uint32 reqTableType = req->getTableType(); + const bool reqListNames = req->getListNames(); + const bool reqListIndexes = req->getListIndexes(); + // init the confs + ListTablesConf * conf = (ListTablesConf *)signal->getDataPtrSend(); + conf->senderData = senderData; + conf->counter = 0; + Uint32 pos = 0; + for (i = 0; i < c_tableRecordPool.getSize(); i++) { + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, i); + // filter + if (tablePtr.p->tabState == TableRecord::NOT_DEFINED || + tablePtr.p->tabState == TableRecord::REORG_TABLE_PREPARED) + continue; + + + if ((reqTableType != (Uint32)0) && (reqTableType != (unsigned)tablePtr.p->tableType)) + continue; + if (reqListIndexes && reqTableId != tablePtr.p->primaryTableId) + continue; + conf->tableData[pos] = 0; + // id + conf->setTableId(pos, tablePtr.i); + // type + conf->setTableType(pos, tablePtr.p->tableType); + // state + if (tablePtr.p->isTable()) { + switch (tablePtr.p->tabState) { + case TableRecord::DEFINING: + case TableRecord::CHECKED: + conf->setTableState(pos, DictTabInfo::StateBuilding); + break; + case TableRecord::PREPARE_DROPPING: + case TableRecord::DROPPING: + conf->setTableState(pos, DictTabInfo::StateDropping); + break; + case TableRecord::DEFINED: + conf->setTableState(pos, DictTabInfo::StateOnline); + break; + default: + conf->setTableState(pos, DictTabInfo::StateBroken); + break; + } + } + if (tablePtr.p->isIndex()) { + switch (tablePtr.p->indexState) { + case TableRecord::IS_OFFLINE: + conf->setTableState(pos, DictTabInfo::StateOffline); + break; + case TableRecord::IS_BUILDING: + conf->setTableState(pos, DictTabInfo::StateBuilding); + break; + case TableRecord::IS_DROPPING: + conf->setTableState(pos, DictTabInfo::StateDropping); + break; + case TableRecord::IS_ONLINE: + conf->setTableState(pos, DictTabInfo::StateOnline); + break; + default: + conf->setTableState(pos, DictTabInfo::StateBroken); + break; + } + } + // store + if (! tablePtr.p->storedTable) { + conf->setTableStore(pos, DictTabInfo::StoreTemporary); + } else { + conf->setTableStore(pos, DictTabInfo::StorePermanent); + } + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + if (! reqListNames) + continue; + const Uint32 size = strlen(tablePtr.p->tableName) + 1; + conf->tableData[pos] = size; + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + Uint32 k = 0; + while (k < size) { + char* p = (char*)&conf->tableData[pos]; + for (Uint32 j = 0; j < 4; j++) { + if (k < size) + *p++ = tablePtr.p->tableName[k++]; + else + *p++ = 0; + } + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + } + } + // XXX merge with above somehow + for (i = 0; i < c_triggerRecordPool.getSize(); i++) { + if (reqListIndexes) + break; + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, i); + if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED) + continue; + // constant 10 hardcoded + Uint32 type = 10 + triggerPtr.p->triggerType; + if (reqTableType != 0 && reqTableType != type) + continue; + conf->tableData[pos] = 0; + conf->setTableId(pos, triggerPtr.i); + conf->setTableType(pos, type); + switch (triggerPtr.p->triggerState) { + case TriggerRecord::TS_OFFLINE: + conf->setTableState(pos, DictTabInfo::StateOffline); + break; + case TriggerRecord::TS_ONLINE: + conf->setTableState(pos, DictTabInfo::StateOnline); + break; + default: + conf->setTableState(pos, DictTabInfo::StateBroken); + break; + } + conf->setTableStore(pos, DictTabInfo::StoreTemporary); + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + if (! reqListNames) + continue; + const Uint32 size = strlen(triggerPtr.p->triggerName) + 1; + conf->tableData[pos] = size; + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + Uint32 k = 0; + while (k < size) { + char* p = (char*)&conf->tableData[pos]; + for (Uint32 j = 0; j < 4; j++) { + if (k < size) + *p++ = triggerPtr.p->triggerName[k++]; + else + *p++ = 0; + } + pos++; + if (pos >= ListTablesConf::DataLength) { + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::SignalLength, JBB); + conf->counter++; + pos = 0; + } + } + } + // last signal must have less than max length + sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal, + ListTablesConf::HeaderLength + pos, JBB); +} + +/** + * MODULE: Create index + * + * Create index in DICT via create table operation. Then invoke alter + * index opearation to online the index. + * + * Request type in CREATE_INDX signals: + * + * RT_USER - from API to DICT master + * RT_DICT_PREPARE - prepare participants + * RT_DICT_COMMIT - commit participants + * RT_TC - create index in TC (part of alter index operation) + */ + +void +Dbdict::execCREATE_INDX_REQ(Signal* signal) +{ + jamEntry(); + CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend(); + OpCreateIndexPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const CreateIndxReq::RequestType requestType = req->getRequestType(); + if (requestType == CreateIndxReq::RT_USER) { + jam(); + if (! assembleFragments(signal)) { + jam(); + return; + } + if (signal->getLength() == CreateIndxReq::SignalLength) { + jam(); + if (getOwnNodeId() != c_masterNodeId) { + jam(); + + releaseSections(signal); + OpCreateIndex opBusy; + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = 0; + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_PREPARE; + opPtr.p->m_errorCode = CreateIndxRef::NotMaster; + opPtr.p->m_errorLine = __LINE__; + opPtr.p->m_errorNode = c_masterNodeId; + createIndex_sendReply(signal, opPtr, true); + return; + } + + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_CREATE_INDX_REQ, + signal, CreateIndxReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == CreateIndxReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpCreateIndex opBusy; + if (! c_opCreateIndex.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::Busy; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opCreateIndex.add(opPtr); + // save attribute list + SegmentedSectionPtr ssPtr; + signal->getSection(ssPtr, CreateIndxReq::ATTRIBUTE_LIST_SECTION); + SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); + r0.reset(); // undo implicit first() + if (! r0.getWord(&opPtr.p->m_attrList.sz) || + ! r0.getWords(opPtr.p->m_attrList.id, opPtr.p->m_attrList.sz)) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidName; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + // save name and index table properties + signal->getSection(ssPtr, CreateIndxReq::INDEX_NAME_SECTION); + SimplePropertiesSectionReader r1(ssPtr, getSectionSegmentPool()); + DictTabInfo::Table tableDesc; + tableDesc.init(); + SimpleProperties::UnpackStatus status = SimpleProperties::unpack( + r1, &tableDesc, + DictTabInfo::TableMapping, DictTabInfo::TableMappingSize, + true, true); + if (status != SimpleProperties::Eof) { + opPtr.p->m_errorCode = CreateIndxRef::InvalidName; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + memcpy(opPtr.p->m_indexName, tableDesc.TableName, MAX_TAB_NAME_SIZE); + opPtr.p->m_storedIndex = tableDesc.TableLoggedFlag; + releaseSections(signal); + // master expects to hear from all + if (opPtr.p->m_isMaster) + opPtr.p->m_signalCounter = c_aliveNodes; + createIndex_slavePrepare(signal, opPtr); + createIndex_sendReply(signal, opPtr, false); + return; + } + c_opCreateIndex.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == CreateIndxReq::RT_DICT_COMMIT || + requestType == CreateIndxReq::RT_DICT_ABORT) { + jam(); + if (requestType == CreateIndxReq::RT_DICT_COMMIT) { + opPtr.p->m_request.setIndexId(req->getIndexId()); + opPtr.p->m_request.setIndexVersion(req->getIndexVersion()); + createIndex_slaveCommit(signal, opPtr); + } else { + createIndex_slaveAbort(signal, opPtr); + } + createIndex_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opCreateIndex.release(opPtr); + return; + } + } + jam(); + // return to sender + releaseSections(signal); + OpCreateIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = CreateIndxRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + createIndex_sendReply(signal, opPtr, true); +} + +void +Dbdict::execCREATE_INDX_CONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + CreateIndxConf* conf = (CreateIndxConf*)signal->getDataPtrSend(); + createIndex_recvReply(signal, conf, 0); +} + +void +Dbdict::execCREATE_INDX_REF(Signal* signal) +{ + jamEntry(); + CreateIndxRef* ref = (CreateIndxRef*)signal->getDataPtrSend(); + createIndex_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::createIndex_recvReply(Signal* signal, const CreateIndxConf* conf, + const CreateIndxRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const CreateIndxReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == CreateIndxReq::RT_TC) { + jam(); + // part of alter index operation + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterIndex_fromCreateTc(signal, opPtr); + return; + } + OpCreateIndexPtr opPtr; + c_opCreateIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == CreateIndxReq::RT_DICT_COMMIT || + requestType == CreateIndxReq::RT_DICT_ABORT) { + jam(); + // send reply to user + createIndex_sendReply(signal, opPtr, true); + c_opCreateIndex.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT; + createIndex_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == CreateIndxReq::RT_DICT_PREPARE) { + jam(); + // start index table create + createIndex_toCreateTable(signal, opPtr); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT; + createIndex_sendSlaveReq(signal, opPtr); + return; + } + return; + } + ndbrequire(false); +} + +void +Dbdict::createIndex_slavePrepare(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); +} + +void +Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr) +{ + Uint32 attrid_map[MAX_ATTRIBUTES_IN_INDEX]; + Uint32 k; + jam(); + const CreateIndxReq* const req = &opPtr.p->m_request; + // signal data writer + Uint32* wbuffer = &c_indexPage.word[0]; + LinearWriter w(wbuffer, sizeof(c_indexPage) >> 2); + w.first(); + // get table being indexed + if (! (req->getTableId() < c_tableRecordPool.getSize())) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable; + opPtr.p->m_errorLine = __LINE__; + return; + } + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, req->getTableId()); + if (tablePtr.p->tabState != TableRecord::DEFINED) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (! tablePtr.p->isTable()) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable; + opPtr.p->m_errorLine = __LINE__; + return; + } + // compute index table record + TableRecord indexRec; + TableRecordPtr indexPtr; + indexPtr.i = RNIL; // invalid + indexPtr.p = &indexRec; + initialiseTableRecord(indexPtr); + if (req->getIndexType() == DictTabInfo::UniqueHashIndex) { + indexPtr.p->storedTable = opPtr.p->m_storedIndex; + indexPtr.p->fragmentType = tablePtr.p->fragmentType; + } else if (req->getIndexType() == DictTabInfo::OrderedIndex) { + // first version will not supported logging + if (opPtr.p->m_storedIndex) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType; + opPtr.p->m_errorLine = __LINE__; + return; + } + indexPtr.p->storedTable = false; + // follows table fragmentation + indexPtr.p->fragmentType = tablePtr.p->fragmentType; + } else { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType; + opPtr.p->m_errorLine = __LINE__; + return; + } + indexPtr.p->tableType = (DictTabInfo::TableType)req->getIndexType(); + indexPtr.p->primaryTableId = req->getTableId(); + indexPtr.p->noOfAttributes = opPtr.p->m_attrList.sz; + indexPtr.p->tupKeyLength = 0; + if (indexPtr.p->noOfAttributes == 0) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (indexPtr.p->isOrderedIndex()) { + // tree node size in words (make configurable later) + indexPtr.p->tupKeyLength = MAX_TTREE_NODE_SIZE; + } + + AttributeMask mask; + mask.clear(); + for (k = 0; k < opPtr.p->m_attrList.sz; k++) { + jam(); + unsigned current_id= opPtr.p->m_attrList.id[k]; + AttributeRecord* aRec= NULL; + Uint32 tAttr= tablePtr.p->firstAttribute; + for (; tAttr != RNIL; tAttr= aRec->nextAttrInTable) + { + aRec = c_attributeRecordPool.getPtr(tAttr); + if (aRec->attributeId != current_id) + continue; + jam(); + break; + } + if (tAttr == RNIL) { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (mask.get(current_id)) + { + jam(); + opPtr.p->m_errorCode = CreateIndxRef::DuplicateAttributes; + opPtr.p->m_errorLine = __LINE__; + return; + } + mask.set(current_id); + + const Uint32 a = aRec->attributeDescriptor; + unsigned kk= k; + if (indexPtr.p->isHashIndex()) { + const Uint32 s1 = AttributeDescriptor::getSize(a); + const Uint32 s2 = AttributeDescriptor::getArraySize(a); + indexPtr.p->tupKeyLength += ((1 << s1) * s2 + 31) >> 5; + // reorder the attributes according to the tableid order + // for unque indexes + for (; kk > 0 && current_id < attrid_map[kk-1]>>16; kk--) + attrid_map[kk]= attrid_map[kk-1]; + } + attrid_map[kk]= k | (current_id << 16); + } + indexPtr.p->noOfPrimkey = indexPtr.p->noOfAttributes; + // plus concatenated primary table key attribute + indexPtr.p->noOfAttributes += 1; + indexPtr.p->noOfNullAttr = 0; + // write index table + w.add(DictTabInfo::TableName, opPtr.p->m_indexName); + w.add(DictTabInfo::TableLoggedFlag, indexPtr.p->storedTable); + w.add(DictTabInfo::FragmentTypeVal, indexPtr.p->fragmentType); + w.add(DictTabInfo::TableTypeVal, indexPtr.p->tableType); + w.add(DictTabInfo::PrimaryTable, tablePtr.p->tableName); + w.add(DictTabInfo::PrimaryTableId, tablePtr.i); + w.add(DictTabInfo::NoOfAttributes, indexPtr.p->noOfAttributes); + w.add(DictTabInfo::NoOfKeyAttr, indexPtr.p->noOfPrimkey); + w.add(DictTabInfo::NoOfNullable, indexPtr.p->noOfNullAttr); + w.add(DictTabInfo::KeyLength, indexPtr.p->tupKeyLength); + // write index key attributes + AttributeRecordPtr aRecPtr; + c_attributeRecordPool.getPtr(aRecPtr, tablePtr.p->firstAttribute); + for (k = 0; k < opPtr.p->m_attrList.sz; k++) { + // insert the attributes in the order decided above in attrid_map + // k is new order, current_id is in previous order + // ToDo: make sure "current_id" is stored with the table and + // passed up to NdbDictionary + unsigned current_id= opPtr.p->m_attrList.id[attrid_map[k] & 0xffff]; + jam(); + for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) { + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + tAttr = aRec->nextAttrInTable; + if (aRec->attributeId != current_id) + continue; + jam(); + const Uint32 a = aRec->attributeDescriptor; + bool isNullable = AttributeDescriptor::getNullable(a); + Uint32 attrType = AttributeDescriptor::getType(a); + w.add(DictTabInfo::AttributeName, aRec->attributeName); + w.add(DictTabInfo::AttributeId, k); + if (indexPtr.p->isHashIndex()) { + w.add(DictTabInfo::AttributeKeyFlag, (Uint32)true); + w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false); + } + if (indexPtr.p->isOrderedIndex()) { + w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false); + w.add(DictTabInfo::AttributeNullableFlag, (Uint32)isNullable); + } + w.add(DictTabInfo::AttributeExtType, attrType); + w.add(DictTabInfo::AttributeExtPrecision, aRec->extPrecision); + w.add(DictTabInfo::AttributeExtScale, aRec->extScale); + w.add(DictTabInfo::AttributeExtLength, aRec->extLength); + w.add(DictTabInfo::AttributeEnd, (Uint32)true); + } + } + if (indexPtr.p->isHashIndex()) { + jam(); + // write concatenated primary table key attribute + w.add(DictTabInfo::AttributeName, "NDB$PK"); + w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz); + w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false); + w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false); + w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned); + w.add(DictTabInfo::AttributeExtLength, tablePtr.p->tupKeyLength); + w.add(DictTabInfo::AttributeEnd, (Uint32)true); + } + if (indexPtr.p->isOrderedIndex()) { + jam(); + // write index tree node as Uint32 array attribute + w.add(DictTabInfo::AttributeName, "NDB$TNODE"); + w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz); + w.add(DictTabInfo::AttributeKeyFlag, (Uint32)true); + w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false); + w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned); + w.add(DictTabInfo::AttributeExtLength, indexPtr.p->tupKeyLength); + w.add(DictTabInfo::AttributeEnd, (Uint32)true); + } + // finish + w.add(DictTabInfo::TableEnd, (Uint32)true); + // remember to... + releaseSections(signal); + // send create index table request + CreateTableReq * const cre = (CreateTableReq*)signal->getDataPtrSend(); + cre->senderRef = reference(); + cre->senderData = opPtr.p->key; + LinearSectionPtr lsPtr[3]; + lsPtr[0].p = wbuffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(DBDICT_REF, GSN_CREATE_TABLE_REQ, + signal, CreateTableReq::SignalLength, JBB, lsPtr, 1); +} + +void +Dbdict::createIndex_fromCreateTable(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT; + createIndex_sendSlaveReq(signal, opPtr); + return; + } + if (! opPtr.p->m_request.getOnline()) { + jam(); + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_COMMIT; + createIndex_sendSlaveReq(signal, opPtr); + return; + } + createIndex_toAlterIndex(signal, opPtr); +} + +void +Dbdict::createIndex_toAlterIndex(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(AlterIndxReq::RT_CREATE_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setIndexId(opPtr.p->m_request.getIndexId()); + req->setIndexVersion(opPtr.p->m_request.getIndexVersion()); + req->setOnline(true); + sendSignal(reference(), GSN_ALTER_INDX_REQ, + signal, AlterIndxReq::SignalLength, JBB); +} + +void +Dbdict::createIndex_fromAlterIndex(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT; + createIndex_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = CreateIndxReq::RT_DICT_COMMIT; + createIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::createIndex_slaveCommit(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + const Uint32 indexId = opPtr.p->m_request.getIndexId(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, indexId); + if (! opPtr.p->m_request.getOnline()) { + ndbrequire(indexPtr.p->indexState == TableRecord::IS_UNDEFINED); + indexPtr.p->indexState = TableRecord::IS_OFFLINE; + } else { + ndbrequire(indexPtr.p->indexState == TableRecord::IS_ONLINE); + } +} + +void +Dbdict::createIndex_slaveAbort(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + CreateIndxReq* const req = &opPtr.p->m_request; + const Uint32 indexId = req->getIndexId(); + if (indexId >= c_tableRecordPool.getSize()) { + jam(); + return; + } + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, indexId); + if (! indexPtr.p->isIndex()) { + jam(); + return; + } + indexPtr.p->indexState = TableRecord::IS_BROKEN; +} + +void +Dbdict::createIndex_sendSlaveReq(Signal* signal, OpCreateIndexPtr opPtr) +{ + jam(); + CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + opPtr.p->m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_CREATE_INDX_REQ, + signal, CreateIndxReq::SignalLength, JBB); +} + +void +Dbdict::createIndex_sendReply(Signal* signal, OpCreateIndexPtr opPtr, + bool toUser) +{ + CreateIndxRef* rep = (CreateIndxRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_CREATE_INDX_CONF; + Uint32 length = CreateIndxConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == CreateIndxReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = CreateIndxConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + rep->setIndexVersion(opPtr.p->m_request.getIndexVersion()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) + opPtr.p->m_errorNode = getOwnNodeId(); + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_CREATE_INDX_REF; + length = CreateIndxRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Drop index. + * + * Drop index. First alters the index offline (i.e. drops metadata in + * other blocks) and then drops the index table. + */ + +void +Dbdict::execDROP_INDX_REQ(Signal* signal) +{ + jamEntry(); + DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend(); + OpDropIndexPtr opPtr; + + int err = DropIndxRef::BadRequestType; + const Uint32 senderRef = signal->senderBlockRef(); + const DropIndxReq::RequestType requestType = req->getRequestType(); + if (requestType == DropIndxReq::RT_USER) { + jam(); + if (signal->getLength() == DropIndxReq::SignalLength) { + jam(); + if (getOwnNodeId() != c_masterNodeId) { + jam(); + + err = DropIndxRef::NotMaster; + goto error; + } + // forward initial request plus operation key to all + Uint32 indexId= req->getIndexId(); + Uint32 indexVersion= req->getIndexVersion(); + TableRecordPtr tmp; + int res = getMetaTablePtr(tmp, indexId, indexVersion); + switch(res){ + case MetaData::InvalidArgument: + err = DropIndxRef::IndexNotFound; + goto error; + case MetaData::TableNotFound: + case MetaData::InvalidTableVersion: + err = DropIndxRef::InvalidIndexVersion; + goto error; + } + + if (! tmp.p->isIndex()) { + jam(); + err = DropIndxRef::NotAnIndex; + goto error; + } + + if (tmp.p->indexState == TableRecord::IS_DROPPING){ + jam(); + err = DropIndxRef::IndexNotFound; + goto error; + } + + tmp.p->indexState = TableRecord::IS_DROPPING; + + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_DROP_INDX_REQ, + signal, DropIndxReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == DropIndxReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpDropIndex opBusy; + if (! c_opDropIndex.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = DropIndxReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = DropIndxRef::Busy; + opPtr.p->m_errorLine = __LINE__; + dropIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opDropIndex.add(opPtr); + // master expects to hear from all + if (opPtr.p->m_isMaster) + opPtr.p->m_signalCounter = c_aliveNodes; + dropIndex_slavePrepare(signal, opPtr); + dropIndex_sendReply(signal, opPtr, false); + return; + } + c_opDropIndex.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == DropIndxReq::RT_DICT_COMMIT || + requestType == DropIndxReq::RT_DICT_ABORT) { + jam(); + if (requestType == DropIndxReq::RT_DICT_COMMIT) + dropIndex_slaveCommit(signal, opPtr); + else + dropIndex_slaveAbort(signal, opPtr); + dropIndex_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opDropIndex.release(opPtr); + return; + } + } +error: + jam(); + // return to sender + OpDropIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = (DropIndxRef::ErrorCode)err; + opPtr.p->m_errorLine = __LINE__; + opPtr.p->m_errorNode = c_masterNodeId; + dropIndex_sendReply(signal, opPtr, true); +} + +void +Dbdict::execDROP_INDX_CONF(Signal* signal) +{ + jamEntry(); + DropIndxConf* conf = (DropIndxConf*)signal->getDataPtrSend(); + dropIndex_recvReply(signal, conf, 0); +} + +void +Dbdict::execDROP_INDX_REF(Signal* signal) +{ + jamEntry(); + DropIndxRef* ref = (DropIndxRef*)signal->getDataPtrSend(); + dropIndex_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::dropIndex_recvReply(Signal* signal, const DropIndxConf* conf, + const DropIndxRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const DropIndxReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == DropIndxReq::RT_TC) { + jam(); + // part of alter index operation + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterIndex_fromDropTc(signal, opPtr); + return; + } + OpDropIndexPtr opPtr; + c_opDropIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == DropIndxReq::RT_DICT_COMMIT || + requestType == DropIndxReq::RT_DICT_ABORT) { + jam(); + // send reply to user + dropIndex_sendReply(signal, opPtr, true); + c_opDropIndex.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT; + dropIndex_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == DropIndxReq::RT_DICT_PREPARE) { + jam(); + // start alter offline + dropIndex_toAlterIndex(signal, opPtr); + return; + } + ndbrequire(false); +} + +void +Dbdict::dropIndex_slavePrepare(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + DropIndxReq* const req = &opPtr.p->m_request; + // check index exists + TableRecordPtr indexPtr; + if (! (req->getIndexId() < c_tableRecordPool.getSize())) { + jam(); + opPtr.p->m_errorCode = DropIndxRef::IndexNotFound; + opPtr.p->m_errorLine = __LINE__; + return; + } + c_tableRecordPool.getPtr(indexPtr, req->getIndexId()); + if (indexPtr.p->tabState != TableRecord::DEFINED) { + jam(); + opPtr.p->m_errorCode = DropIndxRef::IndexNotFound; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (! indexPtr.p->isIndex()) { + jam(); + opPtr.p->m_errorCode = DropIndxRef::NotAnIndex; + opPtr.p->m_errorLine = __LINE__; + return; + } + // ignore incoming primary table id + req->setTableId(indexPtr.p->primaryTableId); +} + +void +Dbdict::dropIndex_toAlterIndex(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(AlterIndxReq::RT_DROP_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setIndexId(opPtr.p->m_request.getIndexId()); + req->setIndexVersion(opPtr.p->m_request.getIndexVersion()); + req->setOnline(false); + sendSignal(reference(), GSN_ALTER_INDX_REQ, + signal, AlterIndxReq::SignalLength, JBB); +} + +void +Dbdict::dropIndex_fromAlterIndex(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT; + dropIndex_sendSlaveReq(signal, opPtr); + return; + } + dropIndex_toDropTable(signal, opPtr); +} + +void +Dbdict::dropIndex_toDropTable(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + DropTableReq* const req = (DropTableReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = opPtr.p->key; + req->tableId = opPtr.p->m_request.getIndexId(); + req->tableVersion = opPtr.p->m_request.getIndexVersion(); + sendSignal(reference(), GSN_DROP_TABLE_REQ, + signal,DropTableReq::SignalLength, JBB); +} + +void +Dbdict::dropIndex_fromDropTable(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT; + dropIndex_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = DropIndxReq::RT_DICT_COMMIT; + dropIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::dropIndex_slaveCommit(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); +} + +void +Dbdict::dropIndex_slaveAbort(Signal* signal, OpDropIndexPtr opPtr) +{ + jam(); + DropIndxReq* const req = &opPtr.p->m_request; + const Uint32 indexId = req->getIndexId(); + if (indexId >= c_tableRecordPool.getSize()) { + jam(); + return; + } + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, indexId); + indexPtr.p->indexState = TableRecord::IS_BROKEN; +} + +void +Dbdict::dropIndex_sendSlaveReq(Signal* signal, OpDropIndexPtr opPtr) +{ + DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + opPtr.p->m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_DROP_INDX_REQ, + signal, DropIndxReq::SignalLength, JBB); +} + +void +Dbdict::dropIndex_sendReply(Signal* signal, OpDropIndexPtr opPtr, + bool toUser) +{ + DropIndxRef* rep = (DropIndxRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_DROP_INDX_CONF; + Uint32 length = DropIndxConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == DropIndxReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = DropIndxConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + rep->setIndexVersion(opPtr.p->m_request.getIndexVersion()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) + opPtr.p->m_errorNode = getOwnNodeId(); + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_DROP_INDX_REF; + length = DropIndxRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/***************************************************** + * + * Util signalling + * + *****************************************************/ + +int +Dbdict::sendSignalUtilReq(Callback *pcallback, + BlockReference ref, + GlobalSignalNumber gsn, + Signal* signal, + Uint32 length, + JobBufferLevel jbuf, + LinearSectionPtr ptr[3], + Uint32 noOfSections) +{ + jam(); + EVENT_TRACE; + OpSignalUtilPtr utilRecPtr; + + // Seize a Util Send record + if (!c_opSignalUtil.seize(utilRecPtr)) { + // Failed to allocate util record + return -1; + } + utilRecPtr.p->m_callback = *pcallback; + + // should work for all util signal classes + UtilPrepareReq *req = (UtilPrepareReq*)signal->getDataPtrSend(); + utilRecPtr.p->m_userData = req->getSenderData(); + req->setSenderData(utilRecPtr.i); + + if (ptr) { + jam(); + sendSignal(ref, gsn, signal, length, jbuf, ptr, noOfSections); + } else { + jam(); + sendSignal(ref, gsn, signal, length, jbuf); + } + + return 0; +} + +int +Dbdict::recvSignalUtilReq(Signal* signal, Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + UtilPrepareConf * const req = (UtilPrepareConf*)signal->getDataPtr(); + OpSignalUtilPtr utilRecPtr; + utilRecPtr.i = req->getSenderData(); + if ((utilRecPtr.p = c_opSignalUtil.getPtr(utilRecPtr.i)) == NULL) { + jam(); + return -1; + } + + req->setSenderData(utilRecPtr.p->m_userData); + Callback c = utilRecPtr.p->m_callback; + c_opSignalUtil.release(utilRecPtr); + + execute(signal, c, returnCode); + return 0; +} + +void Dbdict::execUTIL_PREPARE_CONF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + ndbrequire(recvSignalUtilReq(signal, 0) == 0); +} + +void +Dbdict::execUTIL_PREPARE_REF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + ndbrequire(recvSignalUtilReq(signal, 1) == 0); +} + +void Dbdict::execUTIL_EXECUTE_CONF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + ndbrequire(recvSignalUtilReq(signal, 0) == 0); +} + +void Dbdict::execUTIL_EXECUTE_REF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + +#ifdef EVENT_DEBUG + UtilExecuteRef * ref = (UtilExecuteRef *)signal->getDataPtrSend(); + + ndbout_c("execUTIL_EXECUTE_REF"); + ndbout_c("senderData %u",ref->getSenderData()); + ndbout_c("errorCode %u",ref->getErrorCode()); + ndbout_c("TCErrorCode %u",ref->getTCErrorCode()); +#endif + + ndbrequire(recvSignalUtilReq(signal, 1) == 0); +} +void Dbdict::execUTIL_RELEASE_CONF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + ndbrequire(false); + ndbrequire(recvSignalUtilReq(signal, 0) == 0); +} +void Dbdict::execUTIL_RELEASE_REF(Signal *signal) +{ + jamEntry(); + EVENT_TRACE; + ndbrequire(false); + ndbrequire(recvSignalUtilReq(signal, 1) == 0); +} + +/** + * MODULE: Create event + * + * Create event in DICT. + * + * + * Request type in CREATE_EVNT signals: + * + * Signalflow see Dbdict.txt + * + */ + +/***************************************************************** + * + * Systable stuff + * + */ + +const Uint32 Dbdict::sysTab_NDBEVENTS_0_szs[EVENT_SYSTEM_TABLE_LENGTH] = { + sizeof(((sysTab_NDBEVENTS_0*)0)->NAME), + sizeof(((sysTab_NDBEVENTS_0*)0)->EVENT_TYPE), + sizeof(((sysTab_NDBEVENTS_0*)0)->TABLE_NAME), + sizeof(((sysTab_NDBEVENTS_0*)0)->ATTRIBUTE_MASK), + sizeof(((sysTab_NDBEVENTS_0*)0)->SUBID), + sizeof(((sysTab_NDBEVENTS_0*)0)->SUBKEY) +}; + +void +Dbdict::prepareTransactionEventSysTable (Callback *pcallback, + Signal* signal, + Uint32 senderData, + UtilPrepareReq::OperationTypeValue prepReq) +{ + // find table id for event system table + TableRecord keyRecord; + strcpy(keyRecord.tableName, EVENT_SYSTEM_TABLE_NAME); + + TableRecordPtr tablePtr; + c_tableRecordHash.find(tablePtr, keyRecord); + + ndbrequire(tablePtr.i != RNIL); // system table must exist + + Uint32 tableId = tablePtr.p->tableId; /* System table */ + Uint32 noAttr = tablePtr.p->noOfAttributes; + ndbrequire(noAttr == EVENT_SYSTEM_TABLE_LENGTH); + + switch (prepReq) { + case UtilPrepareReq::Update: + case UtilPrepareReq::Insert: + case UtilPrepareReq::Write: + case UtilPrepareReq::Read: + jam(); + break; + case UtilPrepareReq::Delete: + jam(); + noAttr = 1; // only involves Primary key which should be the first + break; + } + prepareUtilTransaction(pcallback, signal, senderData, tableId, NULL, + prepReq, noAttr, NULL, NULL); +} + +void +Dbdict::prepareUtilTransaction(Callback *pcallback, + Signal* signal, + Uint32 senderData, + Uint32 tableId, + const char* tableName, + UtilPrepareReq::OperationTypeValue prepReq, + Uint32 noAttr, + Uint32 attrIds[], + const char *attrNames[]) +{ + jam(); + EVENT_TRACE; + + UtilPrepareReq * utilPrepareReq = + (UtilPrepareReq *)signal->getDataPtrSend(); + + utilPrepareReq->setSenderRef(reference()); + utilPrepareReq->setSenderData(senderData); + + const Uint32 pageSizeInWords = 128; + Uint32 propPage[pageSizeInWords]; + LinearWriter w(&propPage[0],128); + w.first(); + w.add(UtilPrepareReq::NoOfOperations, 1); + w.add(UtilPrepareReq::OperationType, prepReq); + if (tableName) { + jam(); + w.add(UtilPrepareReq::TableName, tableName); + } else { + jam(); + w.add(UtilPrepareReq::TableId, tableId); + } + for(Uint32 i = 0; i < noAttr; i++) + if (tableName) { + jam(); + w.add(UtilPrepareReq::AttributeName, attrNames[i]); + } else { + if (attrIds) { + jam(); + w.add(UtilPrepareReq::AttributeId, attrIds[i]); + } else { + jam(); + w.add(UtilPrepareReq::AttributeId, i); + } + } +#ifdef EVENT_DEBUG + // Debugging + SimplePropertiesLinearReader reader(propPage, w.getWordsUsed()); + printf("Dict::prepareInsertTransactions: Sent SimpleProperties:\n"); + reader.printAll(ndbout); +#endif + + struct LinearSectionPtr sectionsPtr[UtilPrepareReq::NoOfSections]; + sectionsPtr[UtilPrepareReq::PROPERTIES_SECTION].p = propPage; + sectionsPtr[UtilPrepareReq::PROPERTIES_SECTION].sz = w.getWordsUsed(); + + sendSignalUtilReq(pcallback, DBUTIL_REF, GSN_UTIL_PREPARE_REQ, signal, + UtilPrepareReq::SignalLength, JBB, + sectionsPtr, UtilPrepareReq::NoOfSections); +} + +/***************************************************************** + * + * CREATE_EVNT_REQ has three types RT_CREATE, RT_GET (from user) + * and RT_DICT_AFTER_GET send from master DICT to slaves + * + * This function just dscpaches these to + * + * createEvent_RT_USER_CREATE + * createEvent_RT_USER_GET + * createEvent_RT_DICT_AFTER_GET + * + * repectively + * + */ + +void +Dbdict::execCREATE_EVNT_REQ(Signal* signal) +{ + jamEntry(); + +#if 0 + { + SafeCounterHandle handle; + { + SafeCounter tmp(c_counterMgr, handle); + tmp.init<CreateEvntRef>(CMVMI, GSN_DUMP_STATE_ORD, /* senderData */ 13); + tmp.clearWaitingFor(); + tmp.setWaitingFor(3); + ndbrequire(!tmp.done()); + ndbout_c("Allocted"); + } + ndbrequire(!handle.done()); + { + SafeCounter tmp(c_counterMgr, handle); + tmp.clearWaitingFor(3); + ndbrequire(tmp.done()); + ndbout_c("Deallocted"); + } + ndbrequire(handle.done()); + } + { + NodeBitmask nodes; + nodes.clear(); + + nodes.set(2); + nodes.set(3); + nodes.set(4); + nodes.set(5); + + { + Uint32 i = 0; + while((i = nodes.find(i)) != NodeBitmask::NotFound){ + ndbout_c("1 Node id = %u", i); + i++; + } + } + + NodeReceiverGroup rg(DBDICT, nodes); + RequestTracker rt2; + ndbrequire(rt2.done()); + ndbrequire(!rt2.hasRef()); + ndbrequire(!rt2.hasConf()); + rt2.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, 13); + + RequestTracker rt3; + rt3.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, 13); + + ndbrequire(!rt2.done()); + ndbrequire(!rt3.done()); + + rt2.reportRef(c_counterMgr, 2); + rt3.reportConf(c_counterMgr, 2); + + ndbrequire(!rt2.done()); + ndbrequire(!rt3.done()); + + rt2.reportConf(c_counterMgr, 3); + rt3.reportConf(c_counterMgr, 3); + + ndbrequire(!rt2.done()); + ndbrequire(!rt3.done()); + + rt2.reportConf(c_counterMgr, 4); + rt3.reportConf(c_counterMgr, 4); + + ndbrequire(!rt2.done()); + ndbrequire(!rt3.done()); + + rt2.reportConf(c_counterMgr, 5); + rt3.reportConf(c_counterMgr, 5); + + ndbrequire(rt2.done()); + ndbrequire(rt3.done()); + } +#endif + + if (! assembleFragments(signal)) { + jam(); + return; + } + + CreateEvntReq *req = (CreateEvntReq*)signal->getDataPtr(); + const CreateEvntReq::RequestType requestType = req->getRequestType(); + const Uint32 requestFlag = req->getRequestFlag(); + + OpCreateEventPtr evntRecPtr; + // Seize a Create Event record + if (!c_opCreateEvent.seize(evntRecPtr)) { + // Failed to allocate event record + jam(); + releaseSections(signal); + + CreateEvntRef * ret = (CreateEvntRef *)signal->getDataPtrSend(); + ret->senderRef = reference(); + ret->setErrorCode(CreateEvntRef::SeizeError); + ret->setErrorLine(__LINE__); + ret->setErrorNode(reference()); + sendSignal(signal->senderBlockRef(), GSN_CREATE_EVNT_REF, signal, + CreateEvntRef::SignalLength, JBB); + return; + } + +#ifdef EVENT_DEBUG + ndbout_c("DBDICT::execCREATE_EVNT_REQ from %u evntRecId = (%d)", refToNode(signal->getSendersBlockRef()), evntRecPtr.i); +#endif + + ndbrequire(req->getUserRef() == signal->getSendersBlockRef()); + + evntRecPtr.p->init(req,this); + + if (requestFlag & (Uint32)CreateEvntReq::RT_DICT_AFTER_GET) { + jam(); + EVENT_TRACE; + createEvent_RT_DICT_AFTER_GET(signal, evntRecPtr); + return; + } + if (requestType == CreateEvntReq::RT_USER_GET) { + jam(); + EVENT_TRACE; + createEvent_RT_USER_GET(signal, evntRecPtr); + return; + } + if (requestType == CreateEvntReq::RT_USER_CREATE) { + jam(); + EVENT_TRACE; + createEvent_RT_USER_CREATE(signal, evntRecPtr); + return; + } + +#ifdef EVENT_DEBUG + ndbout << "Dbdict.cpp: Dbdict::execCREATE_EVNT_REQ other" << endl; +#endif + jam(); + releaseSections(signal); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); +} + +/******************************************************************** + * + * Event creation + * + *****************************************************************/ + +void +Dbdict::createEvent_RT_USER_CREATE(Signal* signal, OpCreateEventPtr evntRecPtr){ + jam(); + evntRecPtr.p->m_request.setUserRef(signal->senderBlockRef()); + +#ifdef EVENT_DEBUG + ndbout << "Dbdict.cpp: Dbdict::execCREATE_EVNT_REQ RT_USER" << endl; + char buf[128] = {0}; + AttributeMask mask = evntRecPtr.p->m_request.getAttrListBitmask(); + mask.getText(buf); + ndbout_c("mask = %s", buf); +#endif + + // Interpret the long signal + + SegmentedSectionPtr ssPtr; + // save name and event properties + signal->getSection(ssPtr, CreateEvntReq::EVENT_NAME_SECTION); + + SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); +#ifdef EVENT_DEBUG + r0.printAll(ndbout); +#endif + // event name + if ((!r0.first()) || + (r0.getValueType() != SimpleProperties::StringValue) || + (r0.getValueLen() <= 0)) { + jam(); + releaseSections(signal); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); + return; + } + r0.getString(evntRecPtr.p->m_eventRec.NAME); + { + int len = strlen(evntRecPtr.p->m_eventRec.NAME); + memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len); +#ifdef EVENT_DEBUG + printf("CreateEvntReq::RT_USER_CREATE; EventName %s, len %u\n", + evntRecPtr.p->m_eventRec.NAME, len); + for(int i = 0; i < MAX_TAB_NAME_SIZE/4; i++) + printf("H'%.8x ", ((Uint32*)evntRecPtr.p->m_eventRec.NAME)[i]); + printf("\n"); +#endif + } + // table name + if ((!r0.next()) || + (r0.getValueType() != SimpleProperties::StringValue) || + (r0.getValueLen() <= 0)) { + jam(); + releaseSections(signal); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); + return; + } + r0.getString(evntRecPtr.p->m_eventRec.TABLE_NAME); + { + int len = strlen(evntRecPtr.p->m_eventRec.TABLE_NAME); + memset(evntRecPtr.p->m_eventRec.TABLE_NAME+len, 0, MAX_TAB_NAME_SIZE-len); + } + +#ifdef EVENT_DEBUG + ndbout_c("event name: %s",evntRecPtr.p->m_eventRec.NAME); + ndbout_c("table name: %s",evntRecPtr.p->m_eventRec.TABLE_NAME); +#endif + + releaseSections(signal); + + // Send request to SUMA + + CreateSubscriptionIdReq * sumaIdReq = + (CreateSubscriptionIdReq *)signal->getDataPtrSend(); + + // make sure we save the original sender for later + sumaIdReq->senderData = evntRecPtr.i; +#ifdef EVENT_DEBUG + ndbout << "sumaIdReq->senderData = " << sumaIdReq->senderData << endl; +#endif + sendSignal(SUMA_REF, GSN_CREATE_SUBID_REQ, signal, + CreateSubscriptionIdReq::SignalLength, JBB); + // we should now return in either execCREATE_SUBID_CONF + // or execCREATE_SUBID_REF +} + +void Dbdict::execCREATE_SUBID_REF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + CreateSubscriptionIdRef * const ref = + (CreateSubscriptionIdRef *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = ref->senderData; + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); +} + +void Dbdict::execCREATE_SUBID_CONF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + + CreateSubscriptionIdConf const * sumaIdConf = + (CreateSubscriptionIdConf *)signal->getDataPtr(); + + Uint32 evntRecId = sumaIdConf->senderData; + OpCreateEvent *evntRec; + + ndbrequire((evntRec = c_opCreateEvent.getPtr(evntRecId)) != NULL); + + evntRec->m_request.setEventId(sumaIdConf->subscriptionId); + evntRec->m_request.setEventKey(sumaIdConf->subscriptionKey); + + releaseSections(signal); + + Callback c = { safe_cast(&Dbdict::createEventUTIL_PREPARE), 0 }; + + prepareTransactionEventSysTable(&c, signal, evntRecId, + UtilPrepareReq::Insert); +} + +void +Dbdict::createEventComplete_RT_USER_CREATE(Signal* signal, + OpCreateEventPtr evntRecPtr){ + jam(); + createEvent_sendReply(signal, evntRecPtr); +} + +/********************************************************************* + * + * UTIL_PREPARE, UTIL_EXECUTE + * + * insert or read systable NDB$EVENTS_0 + */ + +void interpretUtilPrepareErrorCode(UtilPrepareRef::ErrorCode errorCode, + bool& temporary, Uint32& line) +{ + switch (errorCode) { + case UtilPrepareRef::NO_ERROR: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + case UtilPrepareRef::PREPARE_SEIZE_ERROR: + jam(); + temporary = true; + line = __LINE__; + EVENT_TRACE; + break; + case UtilPrepareRef::PREPARE_PAGES_SEIZE_ERROR: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + case UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + case UtilPrepareRef::DICT_TAB_INFO_ERROR: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + case UtilPrepareRef::MISSING_PROPERTIES_SECTION: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + default: + jam(); + line = __LINE__; + EVENT_TRACE; + break; + } +} + +void +Dbdict::createEventUTIL_PREPARE(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode == 0) { + UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + jam(); + evntRecPtr.i = req->getSenderData(); + const Uint32 prepareId = req->getPrepareId(); + + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + + Callback c = { safe_cast(&Dbdict::createEventUTIL_EXECUTE), 0 }; + + switch (evntRecPtr.p->m_requestType) { + case CreateEvntReq::RT_USER_GET: +#ifdef EVENT_DEBUG + printf("get type = %d\n", CreateEvntReq::RT_USER_GET); +#endif + jam(); + executeTransEventSysTable(&c, signal, + evntRecPtr.i, evntRecPtr.p->m_eventRec, + prepareId, UtilPrepareReq::Read); + break; + case CreateEvntReq::RT_USER_CREATE: +#ifdef EVENT_DEBUG + printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE); +#endif + { + evntRecPtr.p->m_eventRec.EVENT_TYPE = evntRecPtr.p->m_request.getEventType(); + AttributeMask m = evntRecPtr.p->m_request.getAttrListBitmask(); + memcpy(evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK, &m, + sizeof(evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK)); + evntRecPtr.p->m_eventRec.SUBID = evntRecPtr.p->m_request.getEventId(); + evntRecPtr.p->m_eventRec.SUBKEY = evntRecPtr.p->m_request.getEventKey(); + } + jam(); + executeTransEventSysTable(&c, signal, + evntRecPtr.i, evntRecPtr.p->m_eventRec, + prepareId, UtilPrepareReq::Insert); + break; + default: +#ifdef EVENT_DEBUG + printf("type = %d\n", evntRecPtr.p->m_requestType); + printf("bet type = %d\n", CreateEvntReq::RT_USER_GET); + printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE); +#endif + ndbrequire(false); + } + } else { // returnCode != 0 + UtilPrepareRef* const ref = (UtilPrepareRef*)signal->getDataPtr(); + + const UtilPrepareRef::ErrorCode errorCode = + (UtilPrepareRef::ErrorCode)ref->getErrorCode(); + + OpCreateEventPtr evntRecPtr; + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + + bool temporary = false; + interpretUtilPrepareErrorCode(errorCode, + temporary, evntRecPtr.p->m_errorLine); + if (temporary) { + evntRecPtr.p->m_errorCode = + CreateEvntRef::makeTemporary(CreateEvntRef::Undefined); + } + + if (evntRecPtr.p->m_errorCode == 0) { + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + } + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); + } +} + +void Dbdict::executeTransEventSysTable(Callback *pcallback, Signal *signal, + const Uint32 ptrI, + sysTab_NDBEVENTS_0& m_eventRec, + const Uint32 prepareId, + UtilPrepareReq::OperationTypeValue prepReq) +{ + jam(); + const Uint32 noAttr = EVENT_SYSTEM_TABLE_LENGTH; + Uint32 total_len = 0; + + Uint32* attrHdr = signal->theData + 25; + Uint32* attrPtr = attrHdr; + + Uint32 id=0; + // attribute 0 event name: Primary Key + { + AttributeHeader::init(attrPtr, id, sysTab_NDBEVENTS_0_szs[id]/4); + total_len += sysTab_NDBEVENTS_0_szs[id]; + attrPtr++; id++; + } + + switch (prepReq) { + case UtilPrepareReq::Read: + jam(); + EVENT_TRACE; + // no more + while ( id < noAttr ) + AttributeHeader::init(attrPtr++, id++, 0); + ndbrequire(id == (Uint32) noAttr); + break; + case UtilPrepareReq::Insert: + jam(); + EVENT_TRACE; + while ( id < noAttr ) { + AttributeHeader::init(attrPtr, id, sysTab_NDBEVENTS_0_szs[id]/4); + total_len += sysTab_NDBEVENTS_0_szs[id]; + attrPtr++; id++; + } + ndbrequire(id == (Uint32) noAttr); + break; + case UtilPrepareReq::Delete: + ndbrequire(id == 1); + break; + default: + ndbrequire(false); + } + + LinearSectionPtr headerPtr; + LinearSectionPtr dataPtr; + + headerPtr.p = attrHdr; + headerPtr.sz = noAttr; + + dataPtr.p = (Uint32*)&m_eventRec; + dataPtr.sz = total_len/4; + + ndbrequire((total_len == sysTab_NDBEVENTS_0_szs[0]) || + (total_len == sizeof(sysTab_NDBEVENTS_0))); + +#if 0 + printf("Header size %u\n", headerPtr.sz); + for(int i = 0; i < (int)headerPtr.sz; i++) + printf("H'%.8x ", attrHdr[i]); + printf("\n"); + + printf("Data size %u\n", dataPtr.sz); + for(int i = 0; i < (int)dataPtr.sz; i++) + printf("H'%.8x ", dataPage[i]); + printf("\n"); +#endif + + executeTransaction(pcallback, signal, + ptrI, + prepareId, + id, + headerPtr, + dataPtr); +} + +void Dbdict::executeTransaction(Callback *pcallback, + Signal* signal, + Uint32 senderData, + Uint32 prepareId, + Uint32 noAttr, + LinearSectionPtr headerPtr, + LinearSectionPtr dataPtr) +{ + jam(); + EVENT_TRACE; + + UtilExecuteReq * utilExecuteReq = + (UtilExecuteReq *)signal->getDataPtrSend(); + + utilExecuteReq->setSenderRef(reference()); + utilExecuteReq->setSenderData(senderData); + utilExecuteReq->setPrepareId(prepareId); + utilExecuteReq->setReleaseFlag(); // must be done after setting prepareId + +#if 0 + printf("Header size %u\n", headerPtr.sz); + for(int i = 0; i < (int)headerPtr.sz; i++) + printf("H'%.8x ", headerBuffer[i]); + printf("\n"); + + printf("Data size %u\n", dataPtr.sz); + for(int i = 0; i < (int)dataPtr.sz; i++) + printf("H'%.8x ", dataBuffer[i]); + printf("\n"); +#endif + + struct LinearSectionPtr sectionsPtr[UtilExecuteReq::NoOfSections]; + sectionsPtr[UtilExecuteReq::HEADER_SECTION].p = headerPtr.p; + sectionsPtr[UtilExecuteReq::HEADER_SECTION].sz = noAttr; + sectionsPtr[UtilExecuteReq::DATA_SECTION].p = dataPtr.p; + sectionsPtr[UtilExecuteReq::DATA_SECTION].sz = dataPtr.sz; + + sendSignalUtilReq(pcallback, DBUTIL_REF, GSN_UTIL_EXECUTE_REQ, signal, + UtilExecuteReq::SignalLength, JBB, + sectionsPtr, UtilExecuteReq::NoOfSections); +} + +void Dbdict::parseReadEventSys(Signal* signal, sysTab_NDBEVENTS_0& m_eventRec) +{ + SegmentedSectionPtr headerPtr, dataPtr; + jam(); + signal->getSection(headerPtr, UtilExecuteReq::HEADER_SECTION); + SectionReader headerReader(headerPtr, getSectionSegmentPool()); + + signal->getSection(dataPtr, UtilExecuteReq::DATA_SECTION); + SectionReader dataReader(dataPtr, getSectionSegmentPool()); + + AttributeHeader header; + Uint32 *dst = (Uint32*)&m_eventRec; + + for (int i = 0; i < EVENT_SYSTEM_TABLE_LENGTH; i++) { + headerReader.getWord((Uint32 *)&header); + int sz = header.getDataSize(); + for (int i=0; i < sz; i++) + dataReader.getWord(dst++); + } + + ndbrequire( ((char*)dst-(char*)&m_eventRec) == sizeof(m_eventRec) ); + + releaseSections(signal); +} + +void Dbdict::createEventUTIL_EXECUTE(Signal *signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode == 0) { + // Entry into system table all set + UtilExecuteConf* const conf = (UtilExecuteConf*)signal->getDataPtr(); + jam(); + OpCreateEventPtr evntRecPtr; + evntRecPtr.i = conf->getSenderData(); + + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + OpCreateEvent *evntRec = evntRecPtr.p; + + switch (evntRec->m_requestType) { + case CreateEvntReq::RT_USER_GET: { +#ifdef EVENT_DEBUG + printf("get type = %d\n", CreateEvntReq::RT_USER_GET); +#endif + parseReadEventSys(signal, evntRecPtr.p->m_eventRec); + + evntRec->m_request.setEventType(evntRecPtr.p->m_eventRec.EVENT_TYPE); + evntRec->m_request.setAttrListBitmask(*(AttributeMask*)evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK); + evntRec->m_request.setEventId(evntRecPtr.p->m_eventRec.SUBID); + evntRec->m_request.setEventKey(evntRecPtr.p->m_eventRec.SUBKEY); + +#ifdef EVENT_DEBUG + printf("EventName: %s\n", evntRec->m_eventRec.NAME); + printf("TableName: %s\n", evntRec->m_eventRec.TABLE_NAME); +#endif + + // find table id for event table + TableRecord keyRecord; + strcpy(keyRecord.tableName, evntRecPtr.p->m_eventRec.TABLE_NAME); + + TableRecordPtr tablePtr; + c_tableRecordHash.find(tablePtr, keyRecord); + + if (tablePtr.i == RNIL) { + jam(); + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); + return; + } + + evntRec->m_request.setTableId(tablePtr.p->tableId); + + createEventComplete_RT_USER_GET(signal, evntRecPtr); + return; + } + case CreateEvntReq::RT_USER_CREATE: { +#ifdef EVENT_DEBUG + printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE); +#endif + jam(); + createEventComplete_RT_USER_CREATE(signal, evntRecPtr); + return; + } + break; + default: + ndbrequire(false); + } + } else { // returnCode != 0 + UtilExecuteRef * const ref = (UtilExecuteRef *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + jam(); + evntRecPtr.p->m_errorNode = reference(); + evntRecPtr.p->m_errorLine = __LINE__; + + switch (ref->getErrorCode()) { + case UtilExecuteRef::TCError: + switch (ref->getTCErrorCode()) { + case ZNOT_FOUND: + jam(); + evntRecPtr.p->m_errorCode = CreateEvntRef::EventNotFound; + break; + case ZALREADYEXIST: + jam(); + evntRecPtr.p->m_errorCode = CreateEvntRef::EventNameExists; + break; + default: + jam(); + evntRecPtr.p->m_errorCode = CreateEvntRef::UndefinedTCError; + break; + } + break; + default: + jam(); + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + break; + } + + createEvent_sendReply(signal, evntRecPtr); + } +} + +/*********************************************************************** + * + * NdbEventOperation, reading systable, creating event in suma + * + */ + +void +Dbdict::createEvent_RT_USER_GET(Signal* signal, OpCreateEventPtr evntRecPtr){ + jam(); + EVENT_TRACE; +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_REQ::RT_USER_GET evntRecPtr.i = (%d), ref = %u", evntRecPtr.i, evntRecPtr.p->m_request.getUserRef()); +#endif + + SegmentedSectionPtr ssPtr; + + signal->getSection(ssPtr, 0); + + SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); +#ifdef EVENT_DEBUG + r0.printAll(ndbout); +#endif + if ((!r0.first()) || + (r0.getValueType() != SimpleProperties::StringValue) || + (r0.getValueLen() <= 0)) { + jam(); + releaseSections(signal); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); + return; + } + + r0.getString(evntRecPtr.p->m_eventRec.NAME); + int len = strlen(evntRecPtr.p->m_eventRec.NAME); + memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len); + + releaseSections(signal); + + Callback c = { safe_cast(&Dbdict::createEventUTIL_PREPARE), 0 }; + + prepareTransactionEventSysTable(&c, signal, evntRecPtr.i, + UtilPrepareReq::Read); + /* + * Will read systable and fill an OpCreateEventPtr + * and return below + */ +} + +void +Dbdict::createEventComplete_RT_USER_GET(Signal* signal, + OpCreateEventPtr evntRecPtr){ + jam(); + + // Send to oneself and the other DICT's + CreateEvntReq * req = (CreateEvntReq *)signal->getDataPtrSend(); + + *req = evntRecPtr.p->m_request; + req->senderRef = reference(); + req->senderData = evntRecPtr.i; + + req->addRequestFlag(CreateEvntReq::RT_DICT_AFTER_GET); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Coordinator) sending GSN_CREATE_EVNT_REQ::RT_DICT_AFTER_GET to DBDICT participants evntRecPtr.i = (%d)", evntRecPtr.i); +#endif + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + RequestTracker & p = evntRecPtr.p->m_reqTracker; + p.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, evntRecPtr.i); + + sendSignal(rg, GSN_CREATE_EVNT_REQ, signal, CreateEvntReq::SignalLength, JBB); +} + +void +Dbdict::createEvent_nodeFailCallback(Signal* signal, Uint32 eventRecPtrI, + Uint32 returnCode){ + OpCreateEventPtr evntRecPtr; + c_opCreateEvent.getPtr(evntRecPtr, eventRecPtrI); + createEvent_sendReply(signal, evntRecPtr); +} + +void Dbdict::execCREATE_EVNT_REF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + CreateEvntRef * const ref = (CreateEvntRef *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = ref->getUserData(); + + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_REF evntRecPtr.i = (%d)", evntRecPtr.i); +#endif + + if (ref->errorCode == CreateEvntRef::NF_FakeErrorREF){ + jam(); + evntRecPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(ref->senderRef)); + } else { + jam(); + evntRecPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(ref->senderRef)); + } + createEvent_sendReply(signal, evntRecPtr); + + return; +} + +void Dbdict::execCREATE_EVNT_CONF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + CreateEvntConf * const conf = (CreateEvntConf *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = conf->getUserData(); + + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_CONF evntRecPtr.i = (%d)", evntRecPtr.i); +#endif + + evntRecPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(conf->senderRef)); + + // we will only have a valid tablename if it the master DICT sending this + // but that's ok + LinearSectionPtr ptr[1]; + ptr[0].p = (Uint32 *)evntRecPtr.p->m_eventRec.TABLE_NAME; + ptr[0].sz = + (strlen(evntRecPtr.p->m_eventRec.TABLE_NAME)+4)/4; // to make sure we have a null + + createEvent_sendReply(signal, evntRecPtr, ptr, 1); + + return; +} + +/************************************************ + * + * Participant stuff + * + */ + +void +Dbdict::createEvent_RT_DICT_AFTER_GET(Signal* signal, OpCreateEventPtr evntRecPtr){ + jam(); + evntRecPtr.p->m_request.setUserRef(signal->senderBlockRef()); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Participant) got CREATE_EVNT_REQ::RT_DICT_AFTER_GET evntRecPtr.i = (%d)", evntRecPtr.i); +#endif + + // the signal comes from the DICT block that got the first user request! + // This code runs on all DICT nodes, including oneself + + // Seize a Create Event record, the Coordinator will now have two seized + // but that's ok, it's like a recursion + + SubCreateReq * sumaReq = (SubCreateReq *)signal->getDataPtrSend(); + + sumaReq->subscriberRef = reference(); // reference to DICT + sumaReq->subscriberData = evntRecPtr.i; + sumaReq->subscriptionId = evntRecPtr.p->m_request.getEventId(); + sumaReq->subscriptionKey = evntRecPtr.p->m_request.getEventKey(); + sumaReq->subscriptionType = SubCreateReq::TableEvent; + sumaReq->tableId = evntRecPtr.p->m_request.getTableId(); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("sending GSN_SUB_CREATE_REQ"); +#endif + + sendSignal(SUMA_REF, GSN_SUB_CREATE_REQ, signal, + SubCreateReq::SignalLength+1 /*to get table Id*/, JBB); +} + +void Dbdict::execSUB_CREATE_REF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + SubCreateRef * const ref = (SubCreateRef *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = ref->subscriberData; + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Participant) got SUB_CREATE_REF evntRecPtr.i = (%d)", evntRecPtr.i); +#endif + + if (ref->err == GrepError::SUBSCRIPTION_ID_NOT_UNIQUE) { + jam(); +#ifdef EVENT_PH2_DEBUG + ndbout_c("SUBSCRIPTION_ID_NOT_UNIQUE"); +#endif + createEvent_sendReply(signal, evntRecPtr); + return; + } + +#ifdef EVENT_PH2_DEBUG + ndbout_c("Other error"); +#endif + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); +} + +void Dbdict::execSUB_CREATE_CONF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + + SubCreateConf * const sumaConf = (SubCreateConf *)signal->getDataPtr(); + + const Uint32 subscriptionId = sumaConf->subscriptionId; + const Uint32 subscriptionKey = sumaConf->subscriptionKey; + const Uint32 evntRecId = sumaConf->subscriberData; + + OpCreateEvent *evntRec; + ndbrequire((evntRec = c_opCreateEvent.getPtr(evntRecId)) != NULL); + +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT(Participant) got SUB_CREATE_CONF evntRecPtr.i = (%d)", evntRecId); +#endif + + SubSyncReq *sumaSync = (SubSyncReq *)signal->getDataPtrSend(); + + sumaSync->subscriptionId = subscriptionId; + sumaSync->subscriptionKey = subscriptionKey; + sumaSync->part = (Uint32) SubscriptionData::MetaData; + sumaSync->subscriberData = evntRecId; + + sendSignal(SUMA_REF, GSN_SUB_SYNC_REQ, signal, + SubSyncReq::SignalLength, JBB); +} + +void Dbdict::execSUB_SYNC_REF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + SubSyncRef * const ref = (SubSyncRef *)signal->getDataPtr(); + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = ref->subscriberData; + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + createEvent_sendReply(signal, evntRecPtr); +} + +void Dbdict::execSUB_SYNC_CONF(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + + SubSyncConf * const sumaSyncConf = (SubSyncConf *)signal->getDataPtr(); + + // Uint32 subscriptionId = sumaSyncConf->subscriptionId; + // Uint32 subscriptionKey = sumaSyncConf->subscriptionKey; + OpCreateEventPtr evntRecPtr; + + evntRecPtr.i = sumaSyncConf->subscriberData; + ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL); + + ndbrequire(sumaSyncConf->part == (Uint32)SubscriptionData::MetaData); + + createEvent_sendReply(signal, evntRecPtr); +} + +/**************************************************** + * + * common create reply method + * + *******************************************************/ + +void Dbdict::createEvent_sendReply(Signal* signal, + OpCreateEventPtr evntRecPtr, + LinearSectionPtr *ptr, int noLSP) +{ + jam(); + EVENT_TRACE; + + // check if we're ready to sent reply + // if we are the master dict we might be waiting for conf/ref + + if (!evntRecPtr.p->m_reqTracker.done()) { + jam(); + return; // there's more to come + } + + if (evntRecPtr.p->m_reqTracker.hasRef()) { + ptr = NULL; // we don't want to return anything if there's an error + if (!evntRecPtr.p->hasError()) { + evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + jam(); + } else + jam(); + } + + // reference to API if master DICT + // else reference to master DICT + Uint32 senderRef = evntRecPtr.p->m_request.getUserRef(); + Uint32 signalLength; + Uint32 gsn; + + if (evntRecPtr.p->hasError()) { + jam(); + EVENT_TRACE; + CreateEvntRef * ret = (CreateEvntRef *)signal->getDataPtrSend(); + + ret->setEventId(evntRecPtr.p->m_request.getEventId()); + ret->setEventKey(evntRecPtr.p->m_request.getEventKey()); + ret->setUserData(evntRecPtr.p->m_request.getUserData()); + ret->senderRef = reference(); + ret->setTableId(evntRecPtr.p->m_request.getTableId()); + ret->setEventType(evntRecPtr.p->m_request.getEventType()); + ret->setRequestType(evntRecPtr.p->m_request.getRequestType()); + + ret->setErrorCode(evntRecPtr.p->m_errorCode); + ret->setErrorLine(evntRecPtr.p->m_errorLine); + ret->setErrorNode(evntRecPtr.p->m_errorNode); + + signalLength = CreateEvntRef::SignalLength; +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT sending GSN_CREATE_EVNT_REF to evntRecPtr.i = (%d) node = %u ref = %u", evntRecPtr.i, refToNode(senderRef), senderRef); + ndbout_c("errorCode = %u", evntRecPtr.p->m_errorCode); + ndbout_c("errorLine = %u", evntRecPtr.p->m_errorLine); +#endif + gsn = GSN_CREATE_EVNT_REF; + + } else { + jam(); + EVENT_TRACE; + CreateEvntConf * evntConf = (CreateEvntConf *)signal->getDataPtrSend(); + + evntConf->setEventId(evntRecPtr.p->m_request.getEventId()); + evntConf->setEventKey(evntRecPtr.p->m_request.getEventKey()); + evntConf->setUserData(evntRecPtr.p->m_request.getUserData()); + evntConf->senderRef = reference(); + evntConf->setTableId(evntRecPtr.p->m_request.getTableId()); + evntConf->setAttrListBitmask(evntRecPtr.p->m_request.getAttrListBitmask()); + evntConf->setEventType(evntRecPtr.p->m_request.getEventType()); + evntConf->setRequestType(evntRecPtr.p->m_request.getRequestType()); + + signalLength = CreateEvntConf::SignalLength; +#ifdef EVENT_PH2_DEBUG + ndbout_c("DBDICT sending GSN_CREATE_EVNT_CONF to evntRecPtr.i = (%d) node = %u ref = %u", evntRecPtr.i, refToNode(senderRef), senderRef); +#endif + gsn = GSN_CREATE_EVNT_CONF; + } + + if (ptr) { + jam(); + sendSignal(senderRef, gsn, signal, signalLength, JBB, ptr, noLSP); + } else { + jam(); + sendSignal(senderRef, gsn, signal, signalLength, JBB); + } + + c_opCreateEvent.release(evntRecPtr); +} + +/*************************************************************/ + +/******************************************************************** + * + * Start event + * + *******************************************************************/ + +void Dbdict::execSUB_START_REQ(Signal* signal) +{ + jamEntry(); + + Uint32 origSenderRef = signal->senderBlockRef(); + + OpSubEventPtr subbPtr; + if (!c_opSubEvent.seize(subbPtr)) { + SubStartRef * ref = (SubStartRef *)signal->getDataPtrSend(); + { // fix + Uint32 subcriberRef = ((SubStartReq*)signal->getDataPtr())->subscriberRef; + ref->subscriberRef = subcriberRef; + } + jam(); + // ret->setErrorCode(SubStartRef::SeizeError); + // ret->setErrorLine(__LINE__); + // ret->setErrorNode(reference()); + ref->senderRef = reference(); + ref->setTemporary(SubStartRef::Busy); + + sendSignal(origSenderRef, GSN_SUB_START_REF, signal, + SubStartRef::SignalLength2, JBB); + return; + } + + { + const SubStartReq* req = (SubStartReq*) signal->getDataPtr(); + subbPtr.p->m_senderRef = req->senderRef; + subbPtr.p->m_senderData = req->senderData; + subbPtr.p->m_errorCode = 0; + } + + if (refToBlock(origSenderRef) != DBDICT) { + /* + * Coordinator + */ + jam(); + + subbPtr.p->m_senderRef = origSenderRef; // not sure if API sets correctly + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + RequestTracker & p = subbPtr.p->m_reqTracker; + p.init<SubStartRef>(c_counterMgr, rg, GSN_SUB_START_REF, subbPtr.i); + + SubStartReq* req = (SubStartReq*) signal->getDataPtrSend(); + + req->senderRef = reference(); + req->senderData = subbPtr.i; + +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Coordinator) sending GSN_SUB_START_REQ to DBDICT participants subbPtr.i = (%d)", subbPtr.i); +#endif + + sendSignal(rg, GSN_SUB_START_REQ, signal, SubStartReq::SignalLength2, JBB); + return; + } + /* + * Participant + */ + ndbrequire(refToBlock(origSenderRef) == DBDICT); + + { + SubStartReq* req = (SubStartReq*) signal->getDataPtrSend(); + + req->senderRef = reference(); + req->senderData = subbPtr.i; + +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Participant) sending GSN_SUB_START_REQ to SUMA subbPtr.i = (%d)", subbPtr.i); +#endif + sendSignal(SUMA_REF, GSN_SUB_START_REQ, signal, SubStartReq::SignalLength2, JBB); + } +} + +void Dbdict::execSUB_START_REF(Signal* signal) +{ + jamEntry(); + + const SubStartRef* ref = (SubStartRef*) signal->getDataPtr(); + Uint32 senderRef = ref->senderRef; + + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, ref->senderData); + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Participant) got GSN_SUB_START_REF = (%d)", subbPtr.i); +#endif + + if (ref->isTemporary()){ + jam(); + SubStartReq* req = (SubStartReq*)signal->getDataPtrSend(); + { // fix + Uint32 subscriberRef = ref->subscriberRef; + req->subscriberRef = subscriberRef; + } + req->senderRef = reference(); + req->senderData = subbPtr.i; + sendSignal(SUMA_REF, GSN_SUB_START_REQ, + signal, SubStartReq::SignalLength2, JBB); + } else { + jam(); + + SubStartRef* ref = (SubStartRef*) signal->getDataPtrSend(); + ref->senderRef = reference(); + ref->senderData = subbPtr.p->m_senderData; + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_REF, + signal, SubStartRef::SignalLength2, JBB); + c_opSubEvent.release(subbPtr); + } + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Coordinator) got GSN_SUB_START_REF = (%d)", subbPtr.i); +#endif + if (ref->errorCode == SubStartRef::NF_FakeErrorREF){ + jam(); + subbPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef)); + } else { + jam(); + subbPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef)); + } + completeSubStartReq(signal,subbPtr.i,0); +} + +void Dbdict::execSUB_START_CONF(Signal* signal) +{ + jamEntry(); + + const SubStartConf* conf = (SubStartConf*) signal->getDataPtr(); + Uint32 senderRef = conf->senderRef; + + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, conf->senderData); + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + SubStartConf* conf = (SubStartConf*) signal->getDataPtrSend(); + +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Participant) got GSN_SUB_START_CONF = (%d)", subbPtr.i); +#endif + + conf->senderRef = reference(); + conf->senderData = subbPtr.p->m_senderData; + + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_CONF, + signal, SubStartConf::SignalLength2, JBB); + c_opSubEvent.release(subbPtr); + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); +#ifdef EVENT_PH3_DEBUG + ndbout_c("DBDICT(Coordinator) got GSN_SUB_START_CONF = (%d)", subbPtr.i); +#endif + subbPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef)); + completeSubStartReq(signal,subbPtr.i,0); +} + +/* + * Coordinator + */ +void Dbdict::completeSubStartReq(Signal* signal, + Uint32 ptrI, + Uint32 returnCode){ + jam(); + + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, ptrI); + + if (!subbPtr.p->m_reqTracker.done()){ + jam(); + return; + } + + if (subbPtr.p->m_reqTracker.hasRef()) { + jam(); +#ifdef EVENT_DEBUG + ndbout_c("SUB_START_REF"); +#endif + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_REF, + signal, SubStartRef::SignalLength, JBB); + if (subbPtr.p->m_reqTracker.hasConf()) { + // stopStartedNodes(signal); + } + c_opSubEvent.release(subbPtr); + return; + } +#ifdef EVENT_DEBUG + ndbout_c("SUB_START_CONF"); +#endif + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_CONF, + signal, SubStartConf::SignalLength, JBB); + c_opSubEvent.release(subbPtr); +} + +/******************************************************************** + * + * Stop event + * + *******************************************************************/ + +void Dbdict::execSUB_STOP_REQ(Signal* signal) +{ + jamEntry(); + + Uint32 origSenderRef = signal->senderBlockRef(); + + OpSubEventPtr subbPtr; + if (!c_opSubEvent.seize(subbPtr)) { + SubStopRef * ref = (SubStopRef *)signal->getDataPtrSend(); + jam(); + // ret->setErrorCode(SubStartRef::SeizeError); + // ret->setErrorLine(__LINE__); + // ret->setErrorNode(reference()); + ref->senderRef = reference(); + ref->setTemporary(SubStopRef::Busy); + + sendSignal(origSenderRef, GSN_SUB_STOP_REF, signal, + SubStopRef::SignalLength, JBB); + return; + } + + { + const SubStopReq* req = (SubStopReq*) signal->getDataPtr(); + subbPtr.p->m_senderRef = req->senderRef; + subbPtr.p->m_senderData = req->senderData; + subbPtr.p->m_errorCode = 0; + } + + if (refToBlock(origSenderRef) != DBDICT) { + /* + * Coordinator + */ + jam(); +#ifdef EVENT_DEBUG + ndbout_c("SUB_STOP_REQ 1"); +#endif + subbPtr.p->m_senderRef = origSenderRef; // not sure if API sets correctly + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + RequestTracker & p = subbPtr.p->m_reqTracker; + p.init<SubStopRef>(c_counterMgr, rg, GSN_SUB_STOP_REF, subbPtr.i); + + SubStopReq* req = (SubStopReq*) signal->getDataPtrSend(); + + req->senderRef = reference(); + req->senderData = subbPtr.i; + + sendSignal(rg, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB); + return; + } + /* + * Participant + */ +#ifdef EVENT_DEBUG + ndbout_c("SUB_STOP_REQ 2"); +#endif + ndbrequire(refToBlock(origSenderRef) == DBDICT); + { + SubStopReq* req = (SubStopReq*) signal->getDataPtrSend(); + + req->senderRef = reference(); + req->senderData = subbPtr.i; + + sendSignal(SUMA_REF, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB); + } +} + +void Dbdict::execSUB_STOP_REF(Signal* signal) +{ + jamEntry(); + const SubStopRef* ref = (SubStopRef*) signal->getDataPtr(); + Uint32 senderRef = ref->senderRef; + + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, ref->senderData); + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + if (ref->isTemporary()){ + jam(); + SubStopReq* req = (SubStopReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = subbPtr.i; + sendSignal(SUMA_REF, GSN_SUB_STOP_REQ, + signal, SubStopReq::SignalLength, JBB); + } else { + jam(); + SubStopRef* ref = (SubStopRef*) signal->getDataPtrSend(); + ref->senderRef = reference(); + ref->senderData = subbPtr.p->m_senderData; + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_REF, + signal, SubStopRef::SignalLength, JBB); + c_opSubEvent.release(subbPtr); + } + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); + if (ref->errorCode == SubStopRef::NF_FakeErrorREF){ + jam(); + subbPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef)); + } else { + jam(); + subbPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef)); + } + completeSubStopReq(signal,subbPtr.i,0); +} + +void Dbdict::execSUB_STOP_CONF(Signal* signal) +{ + jamEntry(); + + const SubStopConf* conf = (SubStopConf*) signal->getDataPtr(); + Uint32 senderRef = conf->senderRef; + + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, conf->senderData); + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + SubStopConf* conf = (SubStopConf*) signal->getDataPtrSend(); + + conf->senderRef = reference(); + conf->senderData = subbPtr.p->m_senderData; + + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_CONF, + signal, SubStopConf::SignalLength, JBB); + c_opSubEvent.release(subbPtr); + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); + subbPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef)); + completeSubStopReq(signal,subbPtr.i,0); +} + +/* + * Coordinator + */ +void Dbdict::completeSubStopReq(Signal* signal, + Uint32 ptrI, + Uint32 returnCode){ + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, ptrI); + + if (!subbPtr.p->m_reqTracker.done()){ + jam(); + return; + } + + if (subbPtr.p->m_reqTracker.hasRef()) { + jam(); +#ifdef EVENT_DEBUG + ndbout_c("SUB_STOP_REF"); +#endif + SubStopRef* ref = (SubStopRef*)signal->getDataPtrSend(); + + ref->senderRef = reference(); + ref->senderData = subbPtr.p->m_senderData; + /* + ref->subscriptionId = subbPtr.p->m_senderData; + ref->subscriptionKey = subbPtr.p->m_senderData; + ref->part = subbPtr.p->m_part; // SubscriptionData::Part + ref->subscriberData = subbPtr.p->m_subscriberData; + ref->subscriberRef = subbPtr.p->m_subscriberRef; + */ + ref->errorCode = subbPtr.p->m_errorCode; + + + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_REF, + signal, SubStopRef::SignalLength, JBB); + if (subbPtr.p->m_reqTracker.hasConf()) { + // stopStartedNodes(signal); + } + c_opSubEvent.release(subbPtr); + return; + } +#ifdef EVENT_DEBUG + ndbout_c("SUB_STOP_CONF"); +#endif + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_CONF, + signal, SubStopConf::SignalLength, JBB); + c_opSubEvent.release(subbPtr); +} + +/*************************************************************** + * MODULE: Drop event. + * + * Drop event. + * + * TODO + */ + +void +Dbdict::execDROP_EVNT_REQ(Signal* signal) +{ + jamEntry(); + EVENT_TRACE; + + DropEvntReq *req = (DropEvntReq*)signal->getDataPtr(); + const Uint32 senderRef = signal->senderBlockRef(); + OpDropEventPtr evntRecPtr; + + // Seize a Create Event record + if (!c_opDropEvent.seize(evntRecPtr)) { + // Failed to allocate event record + jam(); + releaseSections(signal); + + DropEvntRef * ret = (DropEvntRef *)signal->getDataPtrSend(); + ret->setErrorCode(DropEvntRef::SeizeError); + ret->setErrorLine(__LINE__); + ret->setErrorNode(reference()); + sendSignal(senderRef, GSN_DROP_EVNT_REF, signal, + DropEvntRef::SignalLength, JBB); + return; + } + +#ifdef EVENT_DEBUG + ndbout_c("DBDICT::execDROP_EVNT_REQ evntRecId = (%d)", evntRecPtr.i); +#endif + + OpDropEvent* evntRec = evntRecPtr.p; + evntRec->init(req); + + SegmentedSectionPtr ssPtr; + + signal->getSection(ssPtr, 0); + + SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool()); +#ifdef EVENT_DEBUG + r0.printAll(ndbout); +#endif + // event name + if ((!r0.first()) || + (r0.getValueType() != SimpleProperties::StringValue) || + (r0.getValueLen() <= 0)) { + jam(); + releaseSections(signal); + + evntRecPtr.p->m_errorCode = DropEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorNode = reference(); + + dropEvent_sendReply(signal, evntRecPtr); + return; + } + r0.getString(evntRecPtr.p->m_eventRec.NAME); + { + int len = strlen(evntRecPtr.p->m_eventRec.NAME); + memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len); +#ifdef EVENT_DEBUG + printf("DropEvntReq; EventName %s, len %u\n", + evntRecPtr.p->m_eventRec.NAME, len); + for(int i = 0; i < MAX_TAB_NAME_SIZE/4; i++) + printf("H'%.8x ", ((Uint32*)evntRecPtr.p->m_eventRec.NAME)[i]); + printf("\n"); +#endif + } + + releaseSections(signal); + + Callback c = { safe_cast(&Dbdict::dropEventUTIL_PREPARE_READ), 0 }; + + prepareTransactionEventSysTable(&c, signal, evntRecPtr.i, + UtilPrepareReq::Read); +} + +void +Dbdict::dropEventUTIL_PREPARE_READ(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode != 0) { + EVENT_TRACE; + dropEventUtilPrepareRef(signal, callbackData, returnCode); + return; + } + + UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr(); + OpDropEventPtr evntRecPtr; + evntRecPtr.i = req->getSenderData(); + const Uint32 prepareId = req->getPrepareId(); + + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); + + Callback c = { safe_cast(&Dbdict::dropEventUTIL_EXECUTE_READ), 0 }; + + executeTransEventSysTable(&c, signal, + evntRecPtr.i, evntRecPtr.p->m_eventRec, + prepareId, UtilPrepareReq::Read); +} + +void +Dbdict::dropEventUTIL_EXECUTE_READ(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode != 0) { + EVENT_TRACE; + dropEventUtilExecuteRef(signal, callbackData, returnCode); + return; + } + + OpDropEventPtr evntRecPtr; + UtilExecuteConf * const ref = (UtilExecuteConf *)signal->getDataPtr(); + jam(); + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); + + parseReadEventSys(signal, evntRecPtr.p->m_eventRec); + + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + RequestTracker & p = evntRecPtr.p->m_reqTracker; + p.init<SubRemoveRef>(c_counterMgr, rg, GSN_SUB_REMOVE_REF, + evntRecPtr.i); + + SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtrSend(); + + req->senderRef = reference(); + req->senderData = evntRecPtr.i; + req->subscriptionId = evntRecPtr.p->m_eventRec.SUBID; + req->subscriptionKey = evntRecPtr.p->m_eventRec.SUBKEY; + + sendSignal(rg, GSN_SUB_REMOVE_REQ, signal, SubRemoveReq::SignalLength, JBB); +} + +/* + * Participant + */ + +void +Dbdict::execSUB_REMOVE_REQ(Signal* signal) +{ + jamEntry(); + + Uint32 origSenderRef = signal->senderBlockRef(); + + OpSubEventPtr subbPtr; + if (!c_opSubEvent.seize(subbPtr)) { + SubRemoveRef * ref = (SubRemoveRef *)signal->getDataPtrSend(); + jam(); + ref->senderRef = reference(); + ref->setTemporary(SubRemoveRef::Busy); + + sendSignal(origSenderRef, GSN_SUB_REMOVE_REF, signal, + SubRemoveRef::SignalLength, JBB); + return; + } + + { + const SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtr(); + subbPtr.p->m_senderRef = req->senderRef; + subbPtr.p->m_senderData = req->senderData; + subbPtr.p->m_errorCode = 0; + } + + SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = subbPtr.i; + + sendSignal(SUMA_REF, GSN_SUB_REMOVE_REQ, signal, SubRemoveReq::SignalLength, JBB); +} + +/* + * Coordintor/Participant + */ + +void +Dbdict::execSUB_REMOVE_REF(Signal* signal) +{ + jamEntry(); + const SubRemoveRef* ref = (SubRemoveRef*) signal->getDataPtr(); + Uint32 senderRef = ref->senderRef; + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, ref->senderData); + if (ref->errorCode == (Uint32) GrepError::SUBSCRIPTION_ID_NOT_FOUND) { + // conf this since this may occur if a nodefailiure has occured + // earlier so that the systable was not cleared + SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = subbPtr.p->m_senderData; + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_CONF, + signal, SubRemoveConf::SignalLength, JBB); + } else { + SubRemoveRef* ref = (SubRemoveRef*) signal->getDataPtrSend(); + ref->senderRef = reference(); + ref->senderData = subbPtr.p->m_senderData; + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_REF, + signal, SubRemoveRef::SignalLength, JBB); + } + c_opSubEvent.release(subbPtr); + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); + OpDropEventPtr eventRecPtr; + c_opDropEvent.getPtr(eventRecPtr, ref->senderData); + if (ref->errorCode == SubRemoveRef::NF_FakeErrorREF){ + jam(); + eventRecPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef)); + } else { + jam(); + eventRecPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef)); + } + completeSubRemoveReq(signal,eventRecPtr.i,0); +} + +void +Dbdict::execSUB_REMOVE_CONF(Signal* signal) +{ + jamEntry(); + const SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtr(); + Uint32 senderRef = conf->senderRef; + + if (refToBlock(senderRef) == SUMA) { + /* + * Participant + */ + jam(); + OpSubEventPtr subbPtr; + c_opSubEvent.getPtr(subbPtr, conf->senderData); + SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtrSend(); + conf->senderRef = reference(); + conf->senderData = subbPtr.p->m_senderData; + sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_CONF, + signal, SubRemoveConf::SignalLength, JBB); + c_opSubEvent.release(subbPtr); + return; + } + /* + * Coordinator + */ + ndbrequire(refToBlock(senderRef) == DBDICT); + OpDropEventPtr eventRecPtr; + c_opDropEvent.getPtr(eventRecPtr, conf->senderData); + eventRecPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef)); + completeSubRemoveReq(signal,eventRecPtr.i,0); +} + +void +Dbdict::completeSubRemoveReq(Signal* signal, Uint32 ptrI, Uint32 xxx) +{ + OpDropEventPtr evntRecPtr; + c_opDropEvent.getPtr(evntRecPtr, ptrI); + + if (!evntRecPtr.p->m_reqTracker.done()){ + jam(); + return; + } + + if (evntRecPtr.p->m_reqTracker.hasRef()) { + jam(); + evntRecPtr.p->m_errorNode = reference(); + evntRecPtr.p->m_errorLine = __LINE__; + evntRecPtr.p->m_errorCode = DropEvntRef::Undefined; + dropEvent_sendReply(signal, evntRecPtr); + return; + } + + Callback c = { safe_cast(&Dbdict::dropEventUTIL_PREPARE_DELETE), 0 }; + + prepareTransactionEventSysTable(&c, signal, evntRecPtr.i, + UtilPrepareReq::Delete); +} + +void +Dbdict::dropEventUTIL_PREPARE_DELETE(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode != 0) { + EVENT_TRACE; + dropEventUtilPrepareRef(signal, callbackData, returnCode); + return; + } + + UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr(); + OpDropEventPtr evntRecPtr; + jam(); + evntRecPtr.i = req->getSenderData(); + const Uint32 prepareId = req->getPrepareId(); + + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); +#ifdef EVENT_DEBUG + printf("DropEvntUTIL_PREPARE; evntRecPtr.i len %u\n",evntRecPtr.i); +#endif + + Callback c = { safe_cast(&Dbdict::dropEventUTIL_EXECUTE_DELETE), 0 }; + + executeTransEventSysTable(&c, signal, + evntRecPtr.i, evntRecPtr.p->m_eventRec, + prepareId, UtilPrepareReq::Delete); +} + +void +Dbdict::dropEventUTIL_EXECUTE_DELETE(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + if (returnCode != 0) { + EVENT_TRACE; + dropEventUtilExecuteRef(signal, callbackData, returnCode); + return; + } + + OpDropEventPtr evntRecPtr; + UtilExecuteConf * const ref = (UtilExecuteConf *)signal->getDataPtr(); + jam(); + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); + + dropEvent_sendReply(signal, evntRecPtr); +} + +void +Dbdict::dropEventUtilPrepareRef(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + UtilPrepareRef * const ref = (UtilPrepareRef *)signal->getDataPtr(); + OpDropEventPtr evntRecPtr; + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); + + bool temporary = false; + interpretUtilPrepareErrorCode((UtilPrepareRef::ErrorCode)ref->getErrorCode(), + temporary, evntRecPtr.p->m_errorLine); + if (temporary) { + evntRecPtr.p->m_errorCode = (DropEvntRef::ErrorCode) + ((Uint32) DropEvntRef::Undefined | (Uint32) DropEvntRef::Temporary); + } + + if (evntRecPtr.p->m_errorCode == 0) { + evntRecPtr.p->m_errorCode = DropEvntRef::Undefined; + evntRecPtr.p->m_errorLine = __LINE__; + } + evntRecPtr.p->m_errorNode = reference(); + + dropEvent_sendReply(signal, evntRecPtr); +} + +void +Dbdict::dropEventUtilExecuteRef(Signal* signal, + Uint32 callbackData, + Uint32 returnCode) +{ + jam(); + EVENT_TRACE; + OpDropEventPtr evntRecPtr; + UtilExecuteRef * const ref = (UtilExecuteRef *)signal->getDataPtr(); + jam(); + evntRecPtr.i = ref->getSenderData(); + ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL); + + evntRecPtr.p->m_errorNode = reference(); + evntRecPtr.p->m_errorLine = __LINE__; + + switch (ref->getErrorCode()) { + case UtilExecuteRef::TCError: + switch (ref->getTCErrorCode()) { + case ZNOT_FOUND: + jam(); + evntRecPtr.p->m_errorCode = DropEvntRef::EventNotFound; + break; + default: + jam(); + evntRecPtr.p->m_errorCode = DropEvntRef::UndefinedTCError; + break; + } + break; + default: + jam(); + evntRecPtr.p->m_errorCode = DropEvntRef::Undefined; + break; + } + dropEvent_sendReply(signal, evntRecPtr); +} + +void Dbdict::dropEvent_sendReply(Signal* signal, + OpDropEventPtr evntRecPtr) +{ + jam(); + EVENT_TRACE; + Uint32 senderRef = evntRecPtr.p->m_request.getUserRef(); + + if (evntRecPtr.p->hasError()) { + jam(); + DropEvntRef * ret = (DropEvntRef *)signal->getDataPtrSend(); + + ret->setUserData(evntRecPtr.p->m_request.getUserData()); + ret->setUserRef(evntRecPtr.p->m_request.getUserRef()); + + ret->setErrorCode(evntRecPtr.p->m_errorCode); + ret->setErrorLine(evntRecPtr.p->m_errorLine); + ret->setErrorNode(evntRecPtr.p->m_errorNode); + + sendSignal(senderRef, GSN_DROP_EVNT_REF, signal, + DropEvntRef::SignalLength, JBB); + } else { + jam(); + DropEvntConf * evntConf = (DropEvntConf *)signal->getDataPtrSend(); + + evntConf->setUserData(evntRecPtr.p->m_request.getUserData()); + evntConf->setUserRef(evntRecPtr.p->m_request.getUserRef()); + + sendSignal(senderRef, GSN_DROP_EVNT_CONF, signal, + DropEvntConf::SignalLength, JBB); + } + + c_opDropEvent.release(evntRecPtr); +} + +/** + * MODULE: Alter index + * + * Alter index state. Alter online creates the index in each TC and + * then invokes create trigger and alter trigger protocols to activate + * the 3 triggers. Alter offline does the opposite. + * + * Request type received in REQ and returned in CONF/REF: + * + * RT_USER - from API to DICT master + * RT_CREATE_INDEX - part of create index operation + * RT_DROP_INDEX - part of drop index operation + * RT_NODERESTART - node restart, activate locally only + * RT_SYSTEMRESTART - system restart, activate and build if not logged + * RT_DICT_PREPARE - prepare participants + * RT_DICT_TC - to local TC via each participant + * RT_DICT_COMMIT - commit in each participant + */ + +void +Dbdict::execALTER_INDX_REQ(Signal* signal) +{ + jamEntry(); + AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend(); + OpAlterIndexPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const AlterIndxReq::RequestType requestType = req->getRequestType(); + if (requestType == AlterIndxReq::RT_USER || + requestType == AlterIndxReq::RT_CREATE_INDEX || + requestType == AlterIndxReq::RT_DROP_INDEX || + requestType == AlterIndxReq::RT_NODERESTART || + requestType == AlterIndxReq::RT_SYSTEMRESTART) { + jam(); + const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL; + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (isLocal) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } + if (signal->getLength() == AlterIndxReq::SignalLength) { + jam(); + if (! isLocal && getOwnNodeId() != c_masterNodeId) { + jam(); + + releaseSections(signal); + OpAlterIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = AlterIndxRef::NotMaster; + opPtr.p->m_errorLine = __LINE__; + opPtr.p->m_errorNode = c_masterNodeId; + alterIndex_sendReply(signal, opPtr, true); + return; + } + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_ALTER_INDX_REQ, + signal, AlterIndxReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == AlterIndxReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpAlterIndex opBusy; + if (! c_opAlterIndex.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = AlterIndxRef::Busy; + opPtr.p->m_errorLine = __LINE__; + alterIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opAlterIndex.add(opPtr); + // master expects to hear from all + if (opPtr.p->m_isMaster) + opPtr.p->m_signalCounter = receiverNodes; + // check request in all participants + alterIndex_slavePrepare(signal, opPtr); + alterIndex_sendReply(signal, opPtr, false); + return; + } + c_opAlterIndex.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == AlterIndxReq::RT_DICT_TC) { + jam(); + if (opPtr.p->m_request.getOnline()) + alterIndex_toCreateTc(signal, opPtr); + else + alterIndex_toDropTc(signal, opPtr); + return; + } + if (requestType == AlterIndxReq::RT_DICT_COMMIT || + requestType == AlterIndxReq::RT_DICT_ABORT) { + jam(); + if (requestType == AlterIndxReq::RT_DICT_COMMIT) + alterIndex_slaveCommit(signal, opPtr); + else + alterIndex_slaveAbort(signal, opPtr); + alterIndex_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opAlterIndex.release(opPtr); + return; + } + } + jam(); + // return to sender + OpAlterIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = AlterIndxRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + alterIndex_sendReply(signal, opPtr, true); +} + +void +Dbdict::execALTER_INDX_CONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + AlterIndxConf* conf = (AlterIndxConf*)signal->getDataPtrSend(); + alterIndex_recvReply(signal, conf, 0); +} + +void +Dbdict::execALTER_INDX_REF(Signal* signal) +{ + jamEntry(); + AlterIndxRef* ref = (AlterIndxRef*)signal->getDataPtrSend(); + alterIndex_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::alterIndex_recvReply(Signal* signal, const AlterIndxConf* conf, + const AlterIndxRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const AlterIndxReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == AlterIndxReq::RT_CREATE_INDEX) { + jam(); + // part of create index operation + OpCreateIndexPtr opPtr; + c_opCreateIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + createIndex_fromAlterIndex(signal, opPtr); + return; + } + if (requestType == AlterIndxReq::RT_DROP_INDEX) { + jam(); + // part of drop index operation + OpDropIndexPtr opPtr; + c_opDropIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + dropIndex_fromAlterIndex(signal, opPtr); + return; + } + if (requestType == AlterIndxReq::RT_TC || + requestType == AlterIndxReq::RT_TUX) { + jam(); + // part of build index operation + OpBuildIndexPtr opPtr; + c_opBuildIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + buildIndex_fromOnline(signal, opPtr); + return; + } + if (requestType == AlterIndxReq::RT_NODERESTART) { + jam(); + if (ref == 0) { + infoEvent("DICT: index %u activated", (unsigned)key); + } else { + warningEvent("DICT: index %u activation failed: code=%d line=%d", + (unsigned)key, + ref->getErrorCode(), ref->getErrorLine()); + } + activateIndexes(signal, key + 1); + return; + } + if (requestType == AlterIndxReq::RT_SYSTEMRESTART) { + jam(); + if (ref == 0) { + infoEvent("DICT: index %u activated done", (unsigned)key); + } else { + warningEvent("DICT: index %u activated failed: code=%d line=%d node=%d", + (unsigned)key, + ref->getErrorCode(), ref->getErrorLine(), ref->getErrorNode()); + } + activateIndexes(signal, key + 1); + return; + } + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == AlterIndxReq::RT_DICT_COMMIT || + requestType == AlterIndxReq::RT_DICT_ABORT) { + jam(); + // send reply to user + alterIndex_sendReply(signal, opPtr, true); + c_opAlterIndex.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT; + alterIndex_sendSlaveReq(signal, opPtr); + return; + } + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + if (indexPtr.p->isHashIndex()) { + if (requestType == AlterIndxReq::RT_DICT_PREPARE) { + jam(); + if (opPtr.p->m_request.getOnline()) { + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC; + alterIndex_sendSlaveReq(signal, opPtr); + } else { + // start drop triggers + alterIndex_toDropTrigger(signal, opPtr); + } + return; + } + if (requestType == AlterIndxReq::RT_DICT_TC) { + jam(); + if (opPtr.p->m_request.getOnline()) { + // start create triggers + alterIndex_toCreateTrigger(signal, opPtr); + } else { + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT; + alterIndex_sendSlaveReq(signal, opPtr); + } + return; + } + } + if (indexPtr.p->isOrderedIndex()) { + if (requestType == AlterIndxReq::RT_DICT_PREPARE) { + jam(); + if (opPtr.p->m_request.getOnline()) { + // start create triggers + alterIndex_toCreateTrigger(signal, opPtr); + } else { + // start drop triggers + alterIndex_toDropTrigger(signal, opPtr); + } + return; + } + } + ndbrequire(false); +} + +void +Dbdict::alterIndex_slavePrepare(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + const AlterIndxReq* const req = &opPtr.p->m_request; + if (! (req->getIndexId() < c_tableRecordPool.getSize())) { + jam(); + opPtr.p->m_errorCode = AlterIndxRef::Inconsistency; + opPtr.p->m_errorLine = __LINE__; + return; + } + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, req->getIndexId()); + if (indexPtr.p->tabState != TableRecord::DEFINED) { + jam(); + opPtr.p->m_errorCode = AlterIndxRef::IndexNotFound; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (! indexPtr.p->isIndex()) { + jam(); + opPtr.p->m_errorCode = AlterIndxRef::NotAnIndex; + opPtr.p->m_errorLine = __LINE__; + return; + } + if (req->getOnline()) + indexPtr.p->indexState = TableRecord::IS_BUILDING; + else + indexPtr.p->indexState = TableRecord::IS_DROPPING; +} + +void +Dbdict::alterIndex_toCreateTc(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // request to create index in local TC + CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(CreateIndxReq::RT_TC); + req->setIndexType(indexPtr.p->tableType); + req->setTableId(indexPtr.p->primaryTableId); + req->setIndexId(indexPtr.i); + req->setOnline(true); + getIndexAttrList(indexPtr, opPtr.p->m_attrList); + // send + LinearSectionPtr lsPtr[3]; + lsPtr[0].p = (Uint32*)&opPtr.p->m_attrList; + lsPtr[0].sz = 1 + opPtr.p->m_attrList.sz; + sendSignal(calcTcBlockRef(getOwnNodeId()), GSN_CREATE_INDX_REQ, + signal, CreateIndxReq::SignalLength, JBB, lsPtr, 1); +} + +void +Dbdict::alterIndex_fromCreateTc(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + // mark created in local TC + if (! opPtr.p->hasError()) { + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + indexPtr.p->indexLocal |= TableRecord::IL_CREATED_TC; + } + // forward CONF or REF to master + ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC); + alterIndex_sendReply(signal, opPtr, false); +} + +void +Dbdict::alterIndex_toDropTc(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // broken index + if (! (indexPtr.p->indexLocal & TableRecord::IL_CREATED_TC)) { + jam(); + alterIndex_sendReply(signal, opPtr, false); + return; + } + // request to drop in local TC + DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(DropIndxReq::RT_TC); + req->setTableId(indexPtr.p->primaryTableId); + req->setIndexId(indexPtr.i); + req->setIndexVersion(indexPtr.p->tableVersion); + // send + sendSignal(calcTcBlockRef(getOwnNodeId()), GSN_DROP_INDX_REQ, + signal, DropIndxReq::SignalLength, JBB); +} + +void +Dbdict::alterIndex_fromDropTc(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC); + if (! opPtr.p->hasError()) { + // mark dropped in local TC + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + indexPtr.p->indexLocal &= ~TableRecord::IL_CREATED_TC; + } + // forward CONF or REF to master + alterIndex_sendReply(signal, opPtr, false); +} + +void +Dbdict::alterIndex_toCreateTrigger(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // start creation of index triggers + CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(CreateTrigReq::RT_ALTER_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setIndexId(opPtr.p->m_request.getIndexId()); + req->setTriggerId(RNIL); + req->setTriggerActionTime(TriggerActionTime::TA_AFTER); + req->setMonitorAllAttributes(false); + req->setOnline(true); // alter online after create + req->setReceiverRef(0); // implicit for index triggers + getIndexAttrMask(indexPtr, req->getAttributeMask()); + // name section + char triggerName[MAX_TAB_NAME_SIZE]; + Uint32 buffer[2 + ((MAX_TAB_NAME_SIZE + 3) >> 2)]; // SP string + LinearWriter w(buffer, sizeof(buffer) >> 2); + LinearSectionPtr lsPtr[3]; + if (indexPtr.p->isHashIndex()) { + req->setTriggerType(TriggerType::SECONDARY_INDEX); + req->setMonitorReplicas(false); + // insert + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) + req->setTriggerId(indexPtr.p->insertTriggerId); + req->setTriggerEvent(TriggerEvent::TE_INSERT); + sprintf(triggerName, "NDB$INDEX_%u_INSERT", opPtr.p->m_request.getIndexId()); + w.reset(); + w.add(CreateTrigReq::TriggerNameKey, triggerName); + lsPtr[0].p = buffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(reference(), GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1); + // update + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) + req->setTriggerId(indexPtr.p->updateTriggerId); + req->setTriggerEvent(TriggerEvent::TE_UPDATE); + sprintf(triggerName, "NDB$INDEX_%u_UPDATE", opPtr.p->m_request.getIndexId()); + w.reset(); + w.add(CreateTrigReq::TriggerNameKey, triggerName); + lsPtr[0].p = buffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(reference(), GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1); + // delete + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) + req->setTriggerId(indexPtr.p->deleteTriggerId); + req->setTriggerEvent(TriggerEvent::TE_DELETE); + sprintf(triggerName, "NDB$INDEX_%u_DELETE", opPtr.p->m_request.getIndexId()); + w.reset(); + w.add(CreateTrigReq::TriggerNameKey, triggerName); + lsPtr[0].p = buffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(reference(), GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1); + // triggers left to create + opPtr.p->m_triggerCounter = 3; + return; + } + if (indexPtr.p->isOrderedIndex()) { + req->addRequestFlag(RequestFlag::RF_NOTCTRIGGER); + req->setTriggerType(TriggerType::ORDERED_INDEX); + req->setTriggerActionTime(TriggerActionTime::TA_CUSTOM); + req->setMonitorReplicas(true); + // one trigger for 5 events (insert, update, delete, commit, abort) + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) + req->setTriggerId(indexPtr.p->customTriggerId); + req->setTriggerEvent(TriggerEvent::TE_CUSTOM); + sprintf(triggerName, "NDB$INDEX_%u_CUSTOM", opPtr.p->m_request.getIndexId()); + w.reset(); + w.add(CreateTrigReq::TriggerNameKey, triggerName); + lsPtr[0].p = buffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(reference(), GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1); + // triggers left to create + opPtr.p->m_triggerCounter = 1; + return; + } + ndbrequire(false); +} + +void +Dbdict::alterIndex_fromCreateTrigger(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + ndbrequire(opPtr.p->m_triggerCounter != 0); + if (--opPtr.p->m_triggerCounter != 0) { + jam(); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT; + alterIndex_sendSlaveReq(signal, opPtr); + return; + } + if(opPtr.p->m_requestType != AlterIndxReq::RT_SYSTEMRESTART){ + // send build request + alterIndex_toBuildIndex(signal, opPtr); + return; + } + + /** + * During system restart, + * leave index in activated but not build state. + * + * Build a bit later when REDO has been run + */ + alterIndex_sendReply(signal, opPtr, true); +} + +void +Dbdict::alterIndex_toDropTrigger(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // start drop of index triggers + DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(DropTrigReq::RT_ALTER_INDEX); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setIndexId(opPtr.p->m_request.getIndexId()); + req->setTriggerInfo(0); // not used + opPtr.p->m_triggerCounter = 0; + // insert + if (indexPtr.p->insertTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->insertTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + // update + if (indexPtr.p->updateTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->updateTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + // delete + if (indexPtr.p->deleteTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->deleteTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + // custom + if (indexPtr.p->customTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->customTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + // build + if (indexPtr.p->buildTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->buildTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + if (opPtr.p->m_triggerCounter == 0) { + // drop in each TC + jam(); + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC; + alterIndex_sendSlaveReq(signal, opPtr); + } +} + +void +Dbdict::alterIndex_fromDropTrigger(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + ndbrequire(opPtr.p->m_triggerCounter != 0); + if (--opPtr.p->m_triggerCounter != 0) { + jam(); + return; + } + // finally drop index in each TC + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + const bool isHashIndex = indexPtr.p->isHashIndex(); + const bool isOrderedIndex = indexPtr.p->isOrderedIndex(); + ndbrequire(isHashIndex != isOrderedIndex); // xor + if (isHashIndex) + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC; + if (isOrderedIndex) + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT; + alterIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::alterIndex_toBuildIndex(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + // get index and table records + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + // build request to self (short signal) + BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(BuildIndxReq::RT_ALTER_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); + req->setBuildId(0); // not used + req->setBuildKey(0); // not used + req->setIndexType(indexPtr.p->tableType); + req->setIndexId(indexPtr.i); + req->setTableId(indexPtr.p->primaryTableId); + req->setParallelism(16); + // send + sendSignal(reference(), GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength, JBB); +} + +void +Dbdict::alterIndex_fromBuildIndex(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT; + alterIndex_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT; + alterIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::alterIndex_slaveCommit(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + // get index record + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + indexPtr.p->indexState = TableRecord::IS_ONLINE; +} + +void +Dbdict::alterIndex_slaveAbort(Signal* signal, OpAlterIndexPtr opPtr) +{ + jam(); + // find index record + const Uint32 indexId = opPtr.p->m_request.getIndexId(); + if (indexId >= c_tableRecordPool.getSize()) + return; + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, indexId); + if (! indexPtr.p->isIndex()) + return; + // mark broken + indexPtr.p->indexState = TableRecord::IS_BROKEN; +} + +void +Dbdict::alterIndex_sendSlaveReq(Signal* signal, OpAlterIndexPtr opPtr) +{ + AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } + opPtr.p->m_signalCounter = receiverNodes; + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_ALTER_INDX_REQ, + signal, AlterIndxReq::SignalLength, JBB); +} + +void +Dbdict::alterIndex_sendReply(Signal* signal, OpAlterIndexPtr opPtr, + bool toUser) +{ + AlterIndxRef* rep = (AlterIndxRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_ALTER_INDX_CONF; + Uint32 length = AlterIndxConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == AlterIndxReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = AlterIndxConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) + opPtr.p->m_errorNode = getOwnNodeId(); + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_ALTER_INDX_REF; + length = AlterIndxRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Build index + * + * Build index or all indexes on a table. Request type: + * + * RT_USER - normal user request, not yet used + * RT_ALTER_INDEX - from alter index + * RT_SYSTEM_RESTART - + * RT_DICT_PREPARE - prepare participants + * RT_DICT_TRIX - to participant on way to local TRIX + * RT_DICT_COMMIT - commit in each participant + * RT_DICT_ABORT - abort + * RT_TRIX - to local TRIX + */ + +void +Dbdict::execBUILDINDXREQ(Signal* signal) +{ + jamEntry(); + BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend(); + OpBuildIndexPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const BuildIndxReq::RequestType requestType = req->getRequestType(); + if (requestType == BuildIndxReq::RT_USER || + requestType == BuildIndxReq::RT_ALTER_INDEX || + requestType == BuildIndxReq::RT_SYSTEMRESTART) { + jam(); + if (signal->getLength() == BuildIndxReq::SignalLength) { + jam(); + if (getOwnNodeId() != c_masterNodeId) { + jam(); + + releaseSections(signal); + OpBuildIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = BuildIndxRef::NotMaster; + opPtr.p->m_errorLine = __LINE__; + opPtr.p->m_errorNode = c_masterNodeId; + buildIndex_sendReply(signal, opPtr, true); + return; + } + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == BuildIndxReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpBuildIndex opBusy; + if (! c_opBuildIndex.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = BuildIndxRef::Busy; + opPtr.p->m_errorLine = __LINE__; + buildIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opBuildIndex.add(opPtr); + // master expects to hear from all + opPtr.p->m_signalCounter = c_aliveNodes; + buildIndex_sendReply(signal, opPtr, false); + return; + } + c_opBuildIndex.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == BuildIndxReq::RT_DICT_TRIX) { + jam(); + buildIndex_buildTrix(signal, opPtr); + return; + } + if (requestType == BuildIndxReq::RT_DICT_TC || + requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); + buildIndex_toOnline(signal, opPtr); + return; + } + if (requestType == BuildIndxReq::RT_DICT_COMMIT || + requestType == BuildIndxReq::RT_DICT_ABORT) { + jam(); + buildIndex_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opBuildIndex.release(opPtr); + return; + } + } + jam(); + // return to sender + OpBuildIndex opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = BuildIndxRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + buildIndex_sendReply(signal, opPtr, true); +} + +void +Dbdict::execBUILDINDXCONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + BuildIndxConf* conf = (BuildIndxConf*)signal->getDataPtrSend(); + buildIndex_recvReply(signal, conf, 0); +} + +void +Dbdict::execBUILDINDXREF(Signal* signal) +{ + jamEntry(); + BuildIndxRef* ref = (BuildIndxRef*)signal->getDataPtrSend(); + buildIndex_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::buildIndex_recvReply(Signal* signal, const BuildIndxConf* conf, + const BuildIndxRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const BuildIndxReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == BuildIndxReq::RT_ALTER_INDEX) { + jam(); + // part of alter index operation + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterIndex_fromBuildIndex(signal, opPtr); + return; + } + + if (requestType == BuildIndxReq::RT_SYSTEMRESTART) { + jam(); + if (ref == 0) { + infoEvent("DICT: index %u rebuild done", (unsigned)key); + } else { + warningEvent("DICT: index %u rebuild failed: code=%d line=%d node=%d", + (unsigned)key, ref->getErrorCode()); + } + rebuildIndexes(signal, key + 1); + return; + } + + OpBuildIndexPtr opPtr; + c_opBuildIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + if (requestType == BuildIndxReq::RT_TRIX) { + jam(); + // forward to master + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX; + buildIndex_sendReply(signal, opPtr, false); + return; + } + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == BuildIndxReq::RT_DICT_COMMIT || + requestType == BuildIndxReq::RT_DICT_ABORT) { + jam(); + // send reply to user + buildIndex_sendReply(signal, opPtr, true); + c_opBuildIndex.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + if (indexPtr.p->isHashIndex()) { + if (requestType == BuildIndxReq::RT_DICT_PREPARE) { + jam(); + if (! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)) { + buildIndex_toCreateConstr(signal, opPtr); + } else { + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TC; + buildIndex_sendSlaveReq(signal, opPtr); + } + return; + } + if (requestType == BuildIndxReq::RT_DICT_TRIX) { + jam(); + ndbrequire(! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)); + buildIndex_toDropConstr(signal, opPtr); + return; + } + if (requestType == BuildIndxReq::RT_DICT_TC) { + jam(); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_COMMIT; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + } + if (indexPtr.p->isOrderedIndex()) { + if (requestType == BuildIndxReq::RT_DICT_PREPARE) { + jam(); + if (! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)) { + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX; + buildIndex_sendSlaveReq(signal, opPtr); + } else { + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TUX; + buildIndex_sendSlaveReq(signal, opPtr); + } + return; + } + if (requestType == BuildIndxReq::RT_DICT_TRIX) { + jam(); + ndbrequire(! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TUX; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_COMMIT; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + } + ndbrequire(false); +} + +void +Dbdict::buildIndex_toCreateConstr(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // request to create constraint trigger + CreateTrigReq* req = (CreateTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(CreateTrigReq::RT_BUILD_INDEX); + req->addRequestFlag(0); // none + req->setTableId(indexPtr.i); + req->setIndexId(RNIL); + req->setTriggerId(RNIL); + req->setTriggerType(TriggerType::READ_ONLY_CONSTRAINT); + req->setTriggerActionTime(TriggerActionTime::TA_AFTER); + req->setTriggerEvent(TriggerEvent::TE_UPDATE); + req->setMonitorReplicas(false); + req->setMonitorAllAttributes(false); + req->setOnline(true); // alter online after create + req->setReceiverRef(0); // no receiver, REF-ed by TUP + req->getAttributeMask().clear(); + // NDB$PK is last attribute + req->getAttributeMask().set(indexPtr.p->noOfAttributes - 1); + // name section + char triggerName[MAX_TAB_NAME_SIZE]; + Uint32 buffer[2 + ((MAX_TAB_NAME_SIZE + 3) >> 2)]; // SP string + LinearWriter w(buffer, sizeof(buffer) >> 2); + LinearSectionPtr lsPtr[3]; + sprintf(triggerName, "NDB$INDEX_%u_BUILD", indexPtr.i); + w.reset(); + w.add(CreateTrigReq::TriggerNameKey, triggerName); + lsPtr[0].p = buffer; + lsPtr[0].sz = w.getWordsUsed(); + sendSignal(reference(), GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1); +} + +void +Dbdict::buildIndex_fromCreateConstr(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX; + buildIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::buildIndex_buildTrix(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + // build request + BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(BuildIndxReq::RT_TRIX); + req->setBuildId(0); // not yet.. + req->setBuildKey(0); // ..in use + req->setIndexType(indexPtr.p->tableType); + req->setIndexId(indexPtr.i); + req->setTableId(indexPtr.p->primaryTableId); + req->setParallelism(16); + if (indexPtr.p->isHashIndex()) { + jam(); + getIndexAttrList(indexPtr, opPtr.p->m_attrList); + getTableKeyList(tablePtr, opPtr.p->m_tableKeyList); + // send + LinearSectionPtr lsPtr[3]; + lsPtr[0].sz = opPtr.p->m_attrList.sz; + lsPtr[0].p = opPtr.p->m_attrList.id; + lsPtr[1].sz = opPtr.p->m_tableKeyList.sz; + lsPtr[1].p = opPtr.p->m_tableKeyList.id; + sendSignal(calcTrixBlockRef(getOwnNodeId()), GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength, JBB, lsPtr, 2); + return; + } + if (indexPtr.p->isOrderedIndex()) { + jam(); + sendSignal(calcTupBlockRef(getOwnNodeId()), GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength, JBB); + return; + } + ndbrequire(false); +} + +void +Dbdict::buildIndex_toDropConstr(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + // request to drop constraint trigger + DropTrigReq* req = (DropTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(DropTrigReq::RT_BUILD_INDEX); + req->addRequestFlag(0); // none + req->setTableId(indexPtr.i); + req->setIndexId(RNIL); + req->setTriggerId(opPtr.p->m_constrTriggerId); + req->setTriggerInfo(0); // not used + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); +} + +void +Dbdict::buildIndex_fromDropConstr(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT; + buildIndex_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TC; + buildIndex_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + // request to set index online in TC or TUX + AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + req->setRequestType(AlterIndxReq::RT_TC); + } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + req->setRequestType(AlterIndxReq::RT_TUX); + } else { + ndbrequire(false); + } + req->setTableId(tablePtr.i); + req->setIndexId(indexPtr.i); + req->setIndexVersion(indexPtr.p->tableVersion); + req->setOnline(true); + BlockReference blockRef = 0; + if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + blockRef = calcTcBlockRef(getOwnNodeId()); + } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + blockRef = calcTuxBlockRef(getOwnNodeId()); + } else { + ndbrequire(false); + } + // send + sendSignal(blockRef, GSN_ALTER_INDX_REQ, + signal, BuildIndxReq::SignalLength, JBB); +} + +void +Dbdict::buildIndex_fromOnline(Signal* signal, OpBuildIndexPtr opPtr) +{ + jam(); + // forward to master + buildIndex_sendReply(signal, opPtr, false); +} + +void +Dbdict::buildIndex_sendSlaveReq(Signal* signal, OpBuildIndexPtr opPtr) +{ + BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + opPtr.p->m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_BUILDINDXREQ, + signal, BuildIndxReq::SignalLength, JBB); +} + +void +Dbdict::buildIndex_sendReply(Signal* signal, OpBuildIndexPtr opPtr, + bool toUser) +{ + BuildIndxRef* rep = (BuildIndxRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_BUILDINDXCONF; + Uint32 length = BuildIndxConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = BuildIndxConf::SignalLength; + } + rep->setIndexType(opPtr.p->m_request.getIndexType()); + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + if (sendRef) { + rep->setErrorCode(opPtr.p->m_errorCode); + rep->masterNodeId = opPtr.p->m_errorNode; + gsn = GSN_BUILDINDXREF; + length = BuildIndxRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Create trigger + * + * Create trigger in all DICT blocks. Optionally start alter trigger + * operation to set the trigger online. + * + * Request type received in REQ and returned in CONF/REF: + * + * RT_USER - normal user e.g. BACKUP + * RT_ALTER_INDEX - from alter index online + * RT_DICT_PREPARE - seize operation in each DICT + * RT_DICT_COMMIT - commit create in each DICT + * RT_TC - sending to TC (operation alter trigger) + * RT_LQH - sending to LQH (operation alter trigger) + */ + +void +Dbdict::execCREATE_TRIG_REQ(Signal* signal) +{ + jamEntry(); + CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend(); + OpCreateTriggerPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const CreateTrigReq::RequestType requestType = req->getRequestType(); + if (requestType == CreateTrigReq::RT_USER || + requestType == CreateTrigReq::RT_ALTER_INDEX || + requestType == CreateTrigReq::RT_BUILD_INDEX) { + jam(); + if (! assembleFragments(signal)) { + jam(); + return; + } + const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL; + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (isLocal) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } + if (signal->getLength() == CreateTrigReq::SignalLength) { + jam(); + if (! isLocal && getOwnNodeId() != c_masterNodeId) { + jam(); + + releaseSections(signal); + OpCreateTrigger opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = CreateTrigRef::NotMaster; + opPtr.p->m_errorLine = __LINE__; + opPtr.p->m_errorNode = c_masterNodeId; + createTrigger_sendReply(signal, opPtr, true); + return; + } + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == CreateTrigReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpCreateTrigger opBusy; + if (! c_opCreateTrigger.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::Busy; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opCreateTrigger.add(opPtr); + { + // save name + SegmentedSectionPtr ssPtr; + signal->getSection(ssPtr, CreateTrigReq::TRIGGER_NAME_SECTION); + SimplePropertiesSectionReader ssReader(ssPtr, getSectionSegmentPool()); + if (ssReader.getKey() != CreateTrigReq::TriggerNameKey || + ! ssReader.getString(opPtr.p->m_triggerName)) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::InvalidName; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + } + releaseSections(signal); + { + // check that trigger name is unique + TriggerRecordPtr triggerPtr; + TriggerRecord keyRecord; + strcpy(keyRecord.triggerName, opPtr.p->m_triggerName); + c_triggerRecordHash.find(triggerPtr, keyRecord); + if (triggerPtr.i != RNIL) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::TriggerExists; + opPtr.p->m_errorLine = __LINE__; + createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + } + + // master expects to hear from all + if (opPtr.p->m_isMaster) + opPtr.p->m_signalCounter = receiverNodes; + // check request in all participants + createTrigger_slavePrepare(signal, opPtr); + createTrigger_sendReply(signal, opPtr, false); + return; + } + c_opCreateTrigger.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == CreateTrigReq::RT_DICT_CREATE) { + jam(); + // master has set trigger id + opPtr.p->m_request.setTriggerId(req->getTriggerId()); + createTrigger_slaveCreate(signal, opPtr); + createTrigger_sendReply(signal, opPtr, false); + return; + } + if (requestType == CreateTrigReq::RT_DICT_COMMIT || + requestType == CreateTrigReq::RT_DICT_ABORT) { + jam(); + if (requestType == CreateTrigReq::RT_DICT_COMMIT) + createTrigger_slaveCommit(signal, opPtr); + else + createTrigger_slaveAbort(signal, opPtr); + createTrigger_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opCreateTrigger.release(opPtr); + return; + } + } + jam(); + // return to sender + releaseSections(signal); + OpCreateTrigger opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = CreateTrigRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + createTrigger_sendReply(signal, opPtr, true); +} + +void +Dbdict::execCREATE_TRIG_CONF(Signal* signal) +{ + jamEntry(); + ndbrequire(signal->getNoOfSections() == 0); + CreateTrigConf* conf = (CreateTrigConf*)signal->getDataPtrSend(); + createTrigger_recvReply(signal, conf, 0); +} + +void +Dbdict::execCREATE_TRIG_REF(Signal* signal) +{ + jamEntry(); + CreateTrigRef* ref = (CreateTrigRef*)signal->getDataPtrSend(); + createTrigger_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::createTrigger_recvReply(Signal* signal, const CreateTrigConf* conf, + const CreateTrigRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const CreateTrigReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == CreateTrigReq::RT_ALTER_INDEX) { + jam(); + // part of alter index operation + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterIndex_fromCreateTrigger(signal, opPtr); + return; + } + if (requestType == CreateTrigReq::RT_BUILD_INDEX) { + jam(); + // part of build index operation + OpBuildIndexPtr opPtr; + c_opBuildIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + // fill in trigger id + opPtr.p->m_constrTriggerId = conf->getTriggerId(); + buildIndex_fromCreateConstr(signal, opPtr); + return; + } + if (requestType == CreateTrigReq::RT_TC || + requestType == CreateTrigReq::RT_LQH) { + jam(); + // part of alter trigger operation + OpAlterTriggerPtr opPtr; + c_opAlterTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterTrigger_fromCreateLocal(signal, opPtr); + return; + } + OpCreateTriggerPtr opPtr; + c_opCreateTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == CreateTrigReq::RT_DICT_COMMIT || + requestType == CreateTrigReq::RT_DICT_ABORT) { + jam(); + // send reply to user + createTrigger_sendReply(signal, opPtr, true); + c_opCreateTrigger.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT; + createTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == CreateTrigReq::RT_DICT_PREPARE) { + jam(); + // seize trigger id in master + createTrigger_masterSeize(signal, opPtr); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT; + createTrigger_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_CREATE; + createTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == CreateTrigReq::RT_DICT_CREATE) { + jam(); + if (opPtr.p->m_request.getOnline()) { + jam(); + // start alter online + createTrigger_toAlterTrigger(signal, opPtr); + return; + } + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_COMMIT; + createTrigger_sendSlaveReq(signal, opPtr); + return; + } + ndbrequire(false); +} + +void +Dbdict::createTrigger_slavePrepare(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); + const CreateTrigReq* const req = &opPtr.p->m_request; + // check trigger type + if (req->getRequestType() == CreateTrigReq::RT_USER && + req->getTriggerType() == TriggerType::SUBSCRIPTION || + req->getRequestType() == CreateTrigReq::RT_ALTER_INDEX && + req->getTriggerType() == TriggerType::SECONDARY_INDEX || + req->getRequestType() == CreateTrigReq::RT_ALTER_INDEX && + req->getTriggerType() == TriggerType::ORDERED_INDEX || + req->getRequestType() == CreateTrigReq::RT_BUILD_INDEX && + req->getTriggerType() == TriggerType::READ_ONLY_CONSTRAINT) { + ; + } else { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::UnsupportedTriggerType; + opPtr.p->m_errorLine = __LINE__; + return; + } + // check the table + const Uint32 tableId = req->getTableId(); + if (! (tableId < c_tableRecordPool.getSize())) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::InvalidTable; + opPtr.p->m_errorLine = __LINE__; + return; + } + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId); + if (tablePtr.p->tabState != TableRecord::DEFINED) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::InvalidTable; + opPtr.p->m_errorLine = __LINE__; + return; + } +} + +void +Dbdict::createTrigger_masterSeize(Signal* signal, OpCreateTriggerPtr opPtr) +{ + TriggerRecordPtr triggerPtr; + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + triggerPtr.i = opPtr.p->m_request.getTriggerId(); + } else { + triggerPtr.i = getFreeTriggerRecord(); + if (triggerPtr.i == RNIL) { + jam(); + opPtr.p->m_errorCode = CreateTrigRef::TooManyTriggers; + opPtr.p->m_errorLine = __LINE__; + return; + } + } + c_triggerRecordPool.getPtr(triggerPtr); + initialiseTriggerRecord(triggerPtr); + triggerPtr.p->triggerState = TriggerRecord::TS_DEFINING; + opPtr.p->m_request.setTriggerId(triggerPtr.i); +} + +void +Dbdict::createTrigger_slaveCreate(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); + const CreateTrigReq* const req = &opPtr.p->m_request; + // get the trigger record + const Uint32 triggerId = req->getTriggerId(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, triggerId); + initialiseTriggerRecord(triggerPtr); + // fill in trigger data + strcpy(triggerPtr.p->triggerName, opPtr.p->m_triggerName); + triggerPtr.p->triggerId = triggerId; + triggerPtr.p->tableId = req->getTableId(); + triggerPtr.p->indexId = RNIL; + triggerPtr.p->triggerType = req->getTriggerType(); + triggerPtr.p->triggerActionTime = req->getTriggerActionTime(); + triggerPtr.p->triggerEvent = req->getTriggerEvent(); + triggerPtr.p->monitorReplicas = req->getMonitorReplicas(); + triggerPtr.p->monitorAllAttributes = req->getMonitorAllAttributes(); + triggerPtr.p->attributeMask = req->getAttributeMask(); + triggerPtr.p->triggerState = TriggerRecord::TS_OFFLINE; + // add to hash table + // ndbout_c("++++++++++++ Adding trigger id %u, %s", triggerPtr.p->triggerId, triggerPtr.p->triggerName); + c_triggerRecordHash.add(triggerPtr); + if (triggerPtr.p->triggerType == TriggerType::SECONDARY_INDEX || + triggerPtr.p->triggerType == TriggerType::ORDERED_INDEX) { + jam(); + // connect to index record XXX should be done in caller instead + triggerPtr.p->indexId = req->getIndexId(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId); + switch (triggerPtr.p->triggerEvent) { + case TriggerEvent::TE_INSERT: + indexPtr.p->insertTriggerId = triggerPtr.p->triggerId; + break; + case TriggerEvent::TE_UPDATE: + indexPtr.p->updateTriggerId = triggerPtr.p->triggerId; + break; + case TriggerEvent::TE_DELETE: + indexPtr.p->deleteTriggerId = triggerPtr.p->triggerId; + break; + case TriggerEvent::TE_CUSTOM: + indexPtr.p->customTriggerId = triggerPtr.p->triggerId; + break; + default: + ndbrequire(false); + break; + } + } + if (triggerPtr.p->triggerType == TriggerType::READ_ONLY_CONSTRAINT) { + jam(); + // connect to index record XXX should be done in caller instead + triggerPtr.p->indexId = req->getTableId(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId); + indexPtr.p->buildTriggerId = triggerPtr.p->triggerId; + } +} + +void +Dbdict::createTrigger_toAlterTrigger(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); + AlterTrigReq* req = (AlterTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(AlterTrigReq::RT_CREATE_TRIGGER); + req->addRequestFlag(opPtr.p->m_requestFlag); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setTriggerId(opPtr.p->m_request.getTriggerId()); + req->setTriggerInfo(0); // not used + req->setOnline(true); + req->setReceiverRef(opPtr.p->m_request.getReceiverRef()); + sendSignal(reference(), GSN_ALTER_TRIG_REQ, + signal, AlterTrigReq::SignalLength, JBB); +} + +void +Dbdict::createTrigger_fromAlterTrigger(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT; + createTrigger_sendSlaveReq(signal, opPtr); + return; + } + opPtr.p->m_requestType = CreateTrigReq::RT_DICT_COMMIT; + createTrigger_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::createTrigger_slaveCommit(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); + const CreateTrigReq* const req = &opPtr.p->m_request; + // get the trigger record + const Uint32 triggerId = req->getTriggerId(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, triggerId); + if (! req->getOnline()) { + triggerPtr.p->triggerState = TriggerRecord::TS_OFFLINE; + } else { + ndbrequire(triggerPtr.p->triggerState == TriggerRecord::TS_ONLINE); + } +} + +void +Dbdict::createTrigger_slaveAbort(Signal* signal, OpCreateTriggerPtr opPtr) +{ + jam(); +} + +void +Dbdict::createTrigger_sendSlaveReq(Signal* signal, OpCreateTriggerPtr opPtr) +{ + CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } + opPtr.p->m_signalCounter = receiverNodes; + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB); +} + +void +Dbdict::createTrigger_sendReply(Signal* signal, OpCreateTriggerPtr opPtr, + bool toUser) +{ + CreateTrigRef* rep = (CreateTrigRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_CREATE_TRIG_CONF; + Uint32 length = CreateTrigConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == CreateTrigReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = CreateTrigConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + rep->setTriggerId(opPtr.p->m_request.getTriggerId()); + rep->setTriggerInfo(opPtr.p->m_request.getTriggerInfo()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) + opPtr.p->m_errorNode = getOwnNodeId(); + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_CREATE_TRIG_REF; + length = CreateTrigRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Drop trigger. + */ + +void +Dbdict::execDROP_TRIG_REQ(Signal* signal) +{ + jamEntry(); + DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend(); + OpDropTriggerPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const DropTrigReq::RequestType requestType = req->getRequestType(); + + if (signal->getNoOfSections() > 0) { + ndbrequire(signal->getNoOfSections() == 1); + jam(); + TriggerRecord keyRecord; + OpDropTrigger opTmp; + opPtr.p=&opTmp; + + SegmentedSectionPtr ssPtr; + signal->getSection(ssPtr, DropTrigReq::TRIGGER_NAME_SECTION); + SimplePropertiesSectionReader ssReader(ssPtr, getSectionSegmentPool()); + if (ssReader.getKey() != DropTrigReq::TriggerNameKey || + ! ssReader.getString(keyRecord.triggerName)) { + jam(); + opPtr.p->m_errorCode = DropTrigRef::InvalidName; + opPtr.p->m_errorLine = __LINE__; + releaseSections(signal); + dropTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + releaseSections(signal); + + TriggerRecordPtr triggerPtr; + + // ndbout_c("++++++++++++++ Looking for trigger %s", keyRecord.triggerName); + c_triggerRecordHash.find(triggerPtr, keyRecord); + if (triggerPtr.i == RNIL) { + jam(); + req->setTriggerId(RNIL); + } else { + jam(); + // ndbout_c("++++++++++ Found trigger %s", triggerPtr.p->triggerName); + req->setTriggerId(triggerPtr.p->triggerId); + req->setTableId(triggerPtr.p->tableId); + } + } + if (requestType == DropTrigReq::RT_USER || + requestType == DropTrigReq::RT_ALTER_INDEX || + requestType == DropTrigReq::RT_BUILD_INDEX) { + jam(); + if (signal->getLength() == DropTrigReq::SignalLength) { + if (getOwnNodeId() != c_masterNodeId) { + jam(); + // forward to DICT master + sendSignal(calcDictBlockRef(c_masterNodeId), GSN_DROP_TRIG_REQ, + signal, signal->getLength(), JBB); + return; + } + if (!c_triggerRecordPool.findId(req->getTriggerId())) { + jam(); + // return to sender + OpDropTrigger opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound; + opPtr.p->m_errorLine = __LINE__; + dropTrigger_sendReply(signal, opPtr, true); + return; + } + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == DropTrigReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpDropTrigger opBusy; + if (! c_opDropTrigger.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = DropTrigReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = DropTrigRef::Busy; + opPtr.p->m_errorLine = __LINE__; + dropTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opDropTrigger.add(opPtr); + // master expects to hear from all + if (opPtr.p->m_isMaster) + opPtr.p->m_signalCounter = c_aliveNodes; + dropTrigger_slavePrepare(signal, opPtr); + dropTrigger_sendReply(signal, opPtr, false); + return; + } + c_opDropTrigger.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == DropTrigReq::RT_DICT_COMMIT || + requestType == DropTrigReq::RT_DICT_ABORT) { + jam(); + if (requestType == DropTrigReq::RT_DICT_COMMIT) + dropTrigger_slaveCommit(signal, opPtr); + else + dropTrigger_slaveAbort(signal, opPtr); + dropTrigger_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opDropTrigger.release(opPtr); + return; + } + } + jam(); + // return to sender + OpDropTrigger opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = DropTrigRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + dropTrigger_sendReply(signal, opPtr, true); +} + +void +Dbdict::execDROP_TRIG_CONF(Signal* signal) +{ + jamEntry(); + DropTrigConf* conf = (DropTrigConf*)signal->getDataPtrSend(); + dropTrigger_recvReply(signal, conf, 0); +} + +void +Dbdict::execDROP_TRIG_REF(Signal* signal) +{ + jamEntry(); + DropTrigRef* ref = (DropTrigRef*)signal->getDataPtrSend(); + dropTrigger_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::dropTrigger_recvReply(Signal* signal, const DropTrigConf* conf, + const DropTrigRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const DropTrigReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == DropTrigReq::RT_ALTER_INDEX) { + jam(); + // part of alter index operation + OpAlterIndexPtr opPtr; + c_opAlterIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterIndex_fromDropTrigger(signal, opPtr); + return; + } + if (requestType == DropTrigReq::RT_BUILD_INDEX) { + jam(); + // part of build index operation + OpBuildIndexPtr opPtr; + c_opBuildIndex.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + buildIndex_fromDropConstr(signal, opPtr); + return; + } + if (requestType == DropTrigReq::RT_TC || + requestType == DropTrigReq::RT_LQH) { + jam(); + // part of alter trigger operation + OpAlterTriggerPtr opPtr; + c_opAlterTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + alterTrigger_fromDropLocal(signal, opPtr); + return; + } + OpDropTriggerPtr opPtr; + c_opDropTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == DropTrigReq::RT_DICT_COMMIT || + requestType == DropTrigReq::RT_DICT_ABORT) { + jam(); + // send reply to user + dropTrigger_sendReply(signal, opPtr, true); + c_opDropTrigger.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = DropTrigReq::RT_DICT_ABORT; + dropTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == DropTrigReq::RT_DICT_PREPARE) { + jam(); + // start alter offline + dropTrigger_toAlterTrigger(signal, opPtr); + return; + } + ndbrequire(false); +} + +void +Dbdict::dropTrigger_slavePrepare(Signal* signal, OpDropTriggerPtr opPtr) +{ + jam(); +} + +void +Dbdict::dropTrigger_toAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr) +{ + jam(); + AlterTrigReq* req = (AlterTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(AlterTrigReq::RT_DROP_TRIGGER); + req->setTableId(opPtr.p->m_request.getTableId()); + req->setTriggerId(opPtr.p->m_request.getTriggerId()); + req->setTriggerInfo(0); // not used + req->setOnline(false); + req->setReceiverRef(0); + sendSignal(reference(), GSN_ALTER_TRIG_REQ, + signal, AlterTrigReq::SignalLength, JBB); +} + +void +Dbdict::dropTrigger_fromAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr) +{ + jam(); + // remove in all + opPtr.p->m_requestType = DropTrigReq::RT_DICT_COMMIT; + dropTrigger_sendSlaveReq(signal, opPtr); +} + +void +Dbdict::dropTrigger_sendSlaveReq(Signal* signal, OpDropTriggerPtr opPtr) +{ + DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + opPtr.p->m_signalCounter = c_aliveNodes; + NodeReceiverGroup rg(DBDICT, c_aliveNodes); + sendSignal(rg, GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); +} + +void +Dbdict::dropTrigger_slaveCommit(Signal* signal, OpDropTriggerPtr opPtr) +{ + jam(); + const DropTrigReq* const req = &opPtr.p->m_request; + // get trigger record + const Uint32 triggerId = req->getTriggerId(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, triggerId); + if (triggerPtr.p->triggerType == TriggerType::SECONDARY_INDEX || + triggerPtr.p->triggerType == TriggerType::ORDERED_INDEX) { + jam(); + // disconnect from index if index trigger XXX move to drop index + triggerPtr.p->indexId = req->getIndexId(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId); + ndbrequire(! indexPtr.isNull()); + switch (triggerPtr.p->triggerEvent) { + case TriggerEvent::TE_INSERT: + indexPtr.p->insertTriggerId = RNIL; + break; + case TriggerEvent::TE_UPDATE: + indexPtr.p->updateTriggerId = RNIL; + break; + case TriggerEvent::TE_DELETE: + indexPtr.p->deleteTriggerId = RNIL; + break; + case TriggerEvent::TE_CUSTOM: + indexPtr.p->customTriggerId = RNIL; + break; + default: + ndbrequire(false); + break; + } + } + if (triggerPtr.p->triggerType == TriggerType::READ_ONLY_CONSTRAINT) { + jam(); + // disconnect from index record XXX should be done in caller instead + triggerPtr.p->indexId = req->getTableId(); + TableRecordPtr indexPtr; + c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId); + indexPtr.p->buildTriggerId = RNIL; + } + // remove trigger + // ndbout_c("++++++++++++ Removing trigger id %u, %s", triggerPtr.p->triggerId, triggerPtr.p->triggerName); + c_triggerRecordHash.remove(triggerPtr); + triggerPtr.p->triggerState = TriggerRecord::TS_NOT_DEFINED; +} + +void +Dbdict::dropTrigger_slaveAbort(Signal* signal, OpDropTriggerPtr opPtr) +{ + jam(); +} + +void +Dbdict::dropTrigger_sendReply(Signal* signal, OpDropTriggerPtr opPtr, + bool toUser) +{ + DropTrigRef* rep = (DropTrigRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_DROP_TRIG_CONF; + Uint32 length = DropTrigConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == DropTrigReq::RT_DICT_ABORT) + sendRef = false; + } else { + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = DropTrigConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setIndexId(opPtr.p->m_request.getIndexId()); + rep->setTriggerId(opPtr.p->m_request.getTriggerId()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) + opPtr.p->m_errorNode = getOwnNodeId(); + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_DROP_TRIG_REF; + length = CreateTrigRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Alter trigger. + * + * Alter trigger state. Alter online creates the trigger first in all + * TC (if index trigger) and then in all LQH-TUP. + * + * Request type received in REQ and returned in CONF/REF: + * + * RT_USER - normal user e.g. BACKUP + * RT_CREATE_TRIGGER - from create trigger + * RT_DROP_TRIGGER - from drop trigger + * RT_DICT_PREPARE - seize operations and check request + * RT_DICT_TC - master to each DICT on way to TC + * RT_DICT_LQH - master to each DICT on way to LQH-TUP + * RT_DICT_COMMIT - commit state change in each DICT (no reply) + */ + +void +Dbdict::execALTER_TRIG_REQ(Signal* signal) +{ + jamEntry(); + AlterTrigReq* const req = (AlterTrigReq*)signal->getDataPtrSend(); + OpAlterTriggerPtr opPtr; + const Uint32 senderRef = signal->senderBlockRef(); + const AlterTrigReq::RequestType requestType = req->getRequestType(); + if (requestType == AlterTrigReq::RT_USER || + requestType == AlterTrigReq::RT_CREATE_TRIGGER || + requestType == AlterTrigReq::RT_DROP_TRIGGER) { + jam(); + const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL; + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (isLocal) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } + if (signal->getLength() == AlterTrigReq::SignalLength) { + jam(); + if (! isLocal && getOwnNodeId() != c_masterNodeId) { + jam(); + // forward to DICT master + sendSignal(calcDictBlockRef(c_masterNodeId), GSN_ALTER_TRIG_REQ, + signal, AlterTrigReq::SignalLength, JBB); + return; + } + // forward initial request plus operation key to all + req->setOpKey(++c_opRecordSequence); + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_ALTER_TRIG_REQ, + signal, AlterTrigReq::SignalLength + 1, JBB); + return; + } + // seize operation record + ndbrequire(signal->getLength() == AlterTrigReq::SignalLength + 1); + const Uint32 opKey = req->getOpKey(); + OpAlterTrigger opBusy; + if (! c_opAlterTrigger.seize(opPtr)) + opPtr.p = &opBusy; + opPtr.p->save(req); + opPtr.p->m_coordinatorRef = senderRef; + opPtr.p->m_isMaster = (senderRef == reference()); + opPtr.p->key = opKey; + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_PREPARE; + if (opPtr.p == &opBusy) { + jam(); + opPtr.p->m_errorCode = AlterTrigRef::Busy; + opPtr.p->m_errorLine = __LINE__; + alterTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster); + return; + } + c_opAlterTrigger.add(opPtr); + // master expects to hear from all + if (opPtr.p->m_isMaster) { + opPtr.p->m_nodes = receiverNodes; + opPtr.p->m_signalCounter = receiverNodes; + } + alterTrigger_slavePrepare(signal, opPtr); + alterTrigger_sendReply(signal, opPtr, false); + return; + } + c_opAlterTrigger.find(opPtr, req->getConnectionPtr()); + if (! opPtr.isNull()) { + opPtr.p->m_requestType = requestType; + if (requestType == AlterTrigReq::RT_DICT_TC || + requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); + if (req->getOnline()) + alterTrigger_toCreateLocal(signal, opPtr); + else + alterTrigger_toDropLocal(signal, opPtr); + return; + } + if (requestType == AlterTrigReq::RT_DICT_COMMIT || + requestType == AlterTrigReq::RT_DICT_ABORT) { + jam(); + if (requestType == AlterTrigReq::RT_DICT_COMMIT) + alterTrigger_slaveCommit(signal, opPtr); + else + alterTrigger_slaveAbort(signal, opPtr); + alterTrigger_sendReply(signal, opPtr, false); + // done in slave + if (! opPtr.p->m_isMaster) + c_opAlterTrigger.release(opPtr); + return; + } + } + jam(); + // return to sender + OpAlterTrigger opBad; + opPtr.p = &opBad; + opPtr.p->save(req); + opPtr.p->m_errorCode = AlterTrigRef::BadRequestType; + opPtr.p->m_errorLine = __LINE__; + alterTrigger_sendReply(signal, opPtr, true); + return; +} + +void +Dbdict::execALTER_TRIG_CONF(Signal* signal) +{ + jamEntry(); + AlterTrigConf* conf = (AlterTrigConf*)signal->getDataPtrSend(); + alterTrigger_recvReply(signal, conf, 0); +} + +void +Dbdict::execALTER_TRIG_REF(Signal* signal) +{ + jamEntry(); + AlterTrigRef* ref = (AlterTrigRef*)signal->getDataPtrSend(); + alterTrigger_recvReply(signal, ref->getConf(), ref); +} + +void +Dbdict::alterTrigger_recvReply(Signal* signal, const AlterTrigConf* conf, + const AlterTrigRef* ref) +{ + jam(); + const Uint32 senderRef = signal->senderBlockRef(); + const AlterTrigReq::RequestType requestType = conf->getRequestType(); + const Uint32 key = conf->getConnectionPtr(); + if (requestType == AlterTrigReq::RT_CREATE_TRIGGER) { + jam(); + // part of create trigger operation + OpCreateTriggerPtr opPtr; + c_opCreateTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + createTrigger_fromAlterTrigger(signal, opPtr); + return; + } + if (requestType == AlterTrigReq::RT_DROP_TRIGGER) { + jam(); + // part of drop trigger operation + OpDropTriggerPtr opPtr; + c_opDropTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + opPtr.p->setError(ref); + dropTrigger_fromAlterTrigger(signal, opPtr); + return; + } + OpAlterTriggerPtr opPtr; + c_opAlterTrigger.find(opPtr, key); + ndbrequire(! opPtr.isNull()); + ndbrequire(opPtr.p->m_isMaster); + ndbrequire(opPtr.p->m_requestType == requestType); + /* + * If refuse on drop trig, because of non-existent trigger, + * comes from anyone but the master node - ignore it and + * remove the node from forter ALTER_TRIG communication + * This will happen if a new node has started since the + * trigger whas created. + */ + if (ref && + refToNode(senderRef) != refToNode(reference()) && + opPtr.p->m_request.getRequestType() == AlterTrigReq::RT_DROP_TRIGGER && + ref->getErrorCode() == AlterTrigRef::TriggerNotFound) { + jam(); + ref = 0; // ignore this error + opPtr.p->m_nodes.clear(refToNode(senderRef)); // remove this from group + } + opPtr.p->setError(ref); + opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef)); + if (! opPtr.p->m_signalCounter.done()) { + jam(); + return; + } + if (requestType == AlterTrigReq::RT_DICT_COMMIT || + requestType == AlterTrigReq::RT_DICT_ABORT) { + jam(); + // send reply to user + alterTrigger_sendReply(signal, opPtr, true); + c_opAlterTrigger.release(opPtr); + return; + } + if (opPtr.p->hasError()) { + jam(); + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_ABORT; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (! (opPtr.p->m_request.getRequestFlag() & RequestFlag::RF_NOTCTRIGGER)) { + if (requestType == AlterTrigReq::RT_DICT_PREPARE) { + jam(); + if (opPtr.p->m_request.getOnline()) + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; + else + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == AlterTrigReq::RT_DICT_TC) { + jam(); + if (opPtr.p->m_request.getOnline()) + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; + else + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); + if (opPtr.p->m_request.getOnline()) + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; + else + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + } else { + if (requestType == AlterTrigReq::RT_DICT_PREPARE) { + jam(); + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + if (requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); + opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; + alterTrigger_sendSlaveReq(signal, opPtr); + return; + } + } + ndbrequire(false); +} + +void +Dbdict::alterTrigger_slavePrepare(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + const AlterTrigReq* const req = &opPtr.p->m_request; + const Uint32 triggerId = req->getTriggerId(); + TriggerRecordPtr triggerPtr; + if (! (triggerId < c_triggerRecordPool.getSize())) { + jam(); + opPtr.p->m_errorCode = AlterTrigRef::TriggerNotFound; + opPtr.p->m_errorLine = __LINE__; + return; + } + c_triggerRecordPool.getPtr(triggerPtr, triggerId); + if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED) { + jam(); + opPtr.p->m_errorCode = AlterTrigRef::TriggerNotFound; + opPtr.p->m_errorLine = __LINE__; + return; + } +} + +void +Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + // find trigger record + const Uint32 triggerId = opPtr.p->m_request.getTriggerId(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, triggerId); + CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + req->setRequestType(CreateTrigReq::RT_TC); + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + req->setRequestType(CreateTrigReq::RT_LQH); + } else { + ndbassert(false); + } + req->setTableId(triggerPtr.p->tableId); + req->setIndexId(triggerPtr.p->indexId); + req->setTriggerId(triggerPtr.i); + req->setTriggerType(triggerPtr.p->triggerType); + req->setTriggerActionTime(triggerPtr.p->triggerActionTime); + req->setTriggerEvent(triggerPtr.p->triggerEvent); + req->setMonitorReplicas(triggerPtr.p->monitorReplicas); + req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes); + req->setOnline(true); + req->setReceiverRef(opPtr.p->m_request.getReceiverRef()); + BlockReference blockRef = 0; + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + blockRef = calcTcBlockRef(getOwnNodeId()); + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + blockRef = calcLqhBlockRef(getOwnNodeId()); + } else { + ndbassert(false); + } + req->setAttributeMask(triggerPtr.p->attributeMask); + sendSignal(blockRef, GSN_CREATE_TRIG_REQ, + signal, CreateTrigReq::SignalLength, JBB); +} + +void +Dbdict::alterTrigger_fromCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + if (! opPtr.p->hasError()) { + // mark created locally + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_TC; + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_LQH; + } else { + ndbrequire(false); + } + } + // forward CONF or REF to master + alterTrigger_sendReply(signal, opPtr, false); +} + +void +Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); + DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend(); + req->setUserRef(reference()); + req->setConnectionPtr(opPtr.p->key); + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + // broken trigger + if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_TC)) { + jam(); + alterTrigger_sendReply(signal, opPtr, false); + return; + } + req->setRequestType(DropTrigReq::RT_TC); + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + // broken trigger + if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_LQH)) { + jam(); + alterTrigger_sendReply(signal, opPtr, false); + return; + } + req->setRequestType(DropTrigReq::RT_LQH); + } else { + ndbassert(false); + } + req->setTableId(triggerPtr.p->tableId); + req->setIndexId(triggerPtr.p->indexId); + req->setTriggerId(triggerPtr.i); + req->setTriggerType(triggerPtr.p->triggerType); + req->setTriggerActionTime(triggerPtr.p->triggerActionTime); + req->setTriggerEvent(triggerPtr.p->triggerEvent); + req->setMonitorReplicas(triggerPtr.p->monitorReplicas); + req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes); + BlockReference blockRef = 0; + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + blockRef = calcTcBlockRef(getOwnNodeId()); + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + blockRef = calcLqhBlockRef(getOwnNodeId()); + } else { + ndbassert(false); + } + sendSignal(blockRef, GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); +} + +void +Dbdict::alterTrigger_fromDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + if (! opPtr.p->hasError()) { + // mark dropped locally + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_TC; + } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_LQH; + } else { + ndbrequire(false); + } + } + // forward CONF or REF to master + alterTrigger_sendReply(signal, opPtr, false); +} + +void +Dbdict::alterTrigger_slaveCommit(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); + TriggerRecordPtr triggerPtr; + c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); + // set state + triggerPtr.p->triggerState = TriggerRecord::TS_ONLINE; +} + +void +Dbdict::alterTrigger_slaveAbort(Signal* signal, OpAlterTriggerPtr opPtr) +{ + jam(); +} + +void +Dbdict::alterTrigger_sendSlaveReq(Signal* signal, OpAlterTriggerPtr opPtr) +{ + AlterTrigReq* const req = (AlterTrigReq*)signal->getDataPtrSend(); + *req = opPtr.p->m_request; + req->setUserRef(opPtr.p->m_coordinatorRef); + req->setConnectionPtr(opPtr.p->key); + req->setRequestType(opPtr.p->m_requestType); + req->addRequestFlag(opPtr.p->m_requestFlag); + NdbNodeBitmask receiverNodes = c_aliveNodes; + if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + receiverNodes.clear(); + receiverNodes.set(getOwnNodeId()); + } else { + opPtr.p->m_nodes.bitAND(receiverNodes); + receiverNodes = opPtr.p->m_nodes; + } + opPtr.p->m_signalCounter = receiverNodes; + NodeReceiverGroup rg(DBDICT, receiverNodes); + sendSignal(rg, GSN_ALTER_TRIG_REQ, + signal, AlterTrigReq::SignalLength, JBB); +} + +void +Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr, + bool toUser) +{ + jam(); + AlterTrigRef* rep = (AlterTrigRef*)signal->getDataPtrSend(); + Uint32 gsn = GSN_ALTER_TRIG_CONF; + Uint32 length = AlterTrigConf::InternalLength; + bool sendRef = opPtr.p->hasError(); + if (! toUser) { + rep->setUserRef(opPtr.p->m_coordinatorRef); + rep->setConnectionPtr(opPtr.p->key); + rep->setRequestType(opPtr.p->m_requestType); + if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_ABORT) { + jam(); + sendRef = false; + } else { + jam(); + } + } else { + jam(); + rep->setUserRef(opPtr.p->m_request.getUserRef()); + rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); + rep->setRequestType(opPtr.p->m_request.getRequestType()); + length = AlterTrigConf::SignalLength; + } + rep->setTableId(opPtr.p->m_request.getTableId()); + rep->setTriggerId(opPtr.p->m_request.getTriggerId()); + if (sendRef) { + if (opPtr.p->m_errorNode == 0) { + jam(); + opPtr.p->m_errorNode = getOwnNodeId(); + } else { + jam(); + } + rep->setErrorCode(opPtr.p->m_errorCode); + rep->setErrorLine(opPtr.p->m_errorLine); + rep->setErrorNode(opPtr.p->m_errorNode); + gsn = GSN_ALTER_TRIG_REF; + length = AlterTrigRef::SignalLength; + } + sendSignal(rep->getUserRef(), gsn, signal, length, JBB); +} + +/** + * MODULE: Support routines for index and trigger. + */ + +void +Dbdict::getTableKeyList(TableRecordPtr tablePtr, AttributeList& list) +{ + jam(); + list.sz = 0; + for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) { + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + if (aRec->tupleKey) + list.id[list.sz++] = aRec->attributeId; + tAttr = aRec->nextAttrInTable; + } +} + +// XXX should store the primary attribute id +void +Dbdict::getIndexAttr(TableRecordPtr indexPtr, Uint32 itAttr, Uint32* id) +{ + jam(); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr); + for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) { + AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); + if (iaRec->equal(*aRec)) { + id[0] = aRec->attributeId; + return; + } + tAttr = aRec->nextAttrInTable; + } + ndbrequire(false); +} + +void +Dbdict::getIndexAttrList(TableRecordPtr indexPtr, AttributeList& list) +{ + jam(); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + list.sz = 0; + memset(list.id, 0, sizeof(list.id)); + ndbrequire(indexPtr.p->noOfAttributes >= 2); + Uint32 itAttr = indexPtr.p->firstAttribute; + for (Uint32 i = 0; i < (Uint32)indexPtr.p->noOfAttributes - 1; i++) { + getIndexAttr(indexPtr, itAttr, &list.id[list.sz++]); + AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr); + itAttr = iaRec->nextAttrInTable; + } +} + +void +Dbdict::getIndexAttrMask(TableRecordPtr indexPtr, AttributeMask& mask) +{ + jam(); + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId); + mask.clear(); + ndbrequire(indexPtr.p->noOfAttributes >= 2); + Uint32 itAttr = indexPtr.p->firstAttribute; + for (Uint32 i = 0; i < (Uint32)indexPtr.p->noOfAttributes - 1; i++) { + Uint32 id; + getIndexAttr(indexPtr, itAttr, &id); + mask.set(id); + AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr); + itAttr = iaRec->nextAttrInTable; + } +} + +/* **************************************************************** */ +/* ---------------------------------------------------------------- */ +/* MODULE: STORE/RESTORE SCHEMA FILE---------------------- */ +/* ---------------------------------------------------------------- */ +/* */ +/* General module used to store the schema file on disk and */ +/* similar function to restore it from disk. */ +/* ---------------------------------------------------------------- */ +/* **************************************************************** */ + +void +Dbdict::initSchemaFile(SchemaFile * sf, Uint32 fileSz){ + memcpy(sf->Magic, "NDBSCHMA", sizeof(sf->Magic)); + sf->ByteOrder = 0x12345678; + sf->NdbVersion = NDB_VERSION; + sf->FileSize = fileSz; + sf->CheckSum = 0; + + Uint32 headSz = (sizeof(SchemaFile)-sizeof(SchemaFile::TableEntry)); + Uint32 noEntries = (fileSz - headSz) / sizeof(SchemaFile::TableEntry); + Uint32 slack = (fileSz - headSz) - noEntries * sizeof(SchemaFile::TableEntry); + + ndbrequire(noEntries > MAX_TABLES); + + sf->NoOfTableEntries = noEntries; + memset(sf->TableEntries, 0, noEntries*sizeof(SchemaFile::TableEntry)); + memset(&(sf->TableEntries[noEntries]), 0, slack); + computeChecksum(sf); +} + +void +Dbdict::computeChecksum(SchemaFile * sf){ + sf->CheckSum = 0; + sf->CheckSum = computeChecksum((const Uint32*)sf, sf->FileSize/4); +} + +bool +Dbdict::validateChecksum(const SchemaFile * sf){ + + Uint32 c = computeChecksum((const Uint32*)sf, sf->FileSize/4); + return c == 0; +} + +Uint32 +Dbdict::computeChecksum(const Uint32 * src, Uint32 len){ + Uint32 ret = 0; + for(Uint32 i = 0; i<len; i++) + ret ^= src[i]; + return ret; +} + +SchemaFile::TableEntry * +Dbdict::getTableEntry(void * p, Uint32 tableId, bool allowTooBig){ + SchemaFile * sf = (SchemaFile*)p; + + ndbrequire(allowTooBig || tableId < sf->NoOfTableEntries); + return &sf->TableEntries[tableId]; +} + +// global metadata support + +int +Dbdict::getMetaTablePtr(TableRecordPtr& tablePtr, Uint32 tableId, Uint32 tableVersion) +{ + if (tableId >= c_tableRecordPool.getSize()) { + return MetaData::InvalidArgument; + } + c_tableRecordPool.getPtr(tablePtr, tableId); + if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) { + return MetaData::TableNotFound; + } + if (tablePtr.p->tableVersion != tableVersion) { + return MetaData::InvalidTableVersion; + } + // online flag is not maintained by DICT + tablePtr.p->online = + tablePtr.p->isTable() && tablePtr.p->tabState == TableRecord::DEFINED || + tablePtr.p->isIndex() && tablePtr.p->indexState == TableRecord::IS_ONLINE; + return 0; +} + +int +Dbdict::getMetaTable(MetaData::Table& table, Uint32 tableId, Uint32 tableVersion) +{ + int ret; + TableRecordPtr tablePtr; + if ((ret = getMetaTablePtr(tablePtr, tableId, tableVersion)) < 0) { + return ret; + } + new (&table) MetaData::Table(*tablePtr.p); + return 0; +} + +int +Dbdict::getMetaTable(MetaData::Table& table, const char* tableName) +{ + int ret; + TableRecordPtr tablePtr; + if (strlen(tableName) + 1 > MAX_TAB_NAME_SIZE) { + return MetaData::InvalidArgument; + } + TableRecord keyRecord; + strcpy(keyRecord.tableName, tableName); + c_tableRecordHash.find(tablePtr, keyRecord); + if (tablePtr.i == RNIL) { + return MetaData::TableNotFound; + } + if ((ret = getMetaTablePtr(tablePtr, tablePtr.i, tablePtr.p->tableVersion)) < 0) { + return ret; + } + new (&table) MetaData::Table(*tablePtr.p); + return 0; +} + +int +Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table, Uint32 attributeId) +{ + int ret; + TableRecordPtr tablePtr; + if ((ret = getMetaTablePtr(tablePtr, table.tableId, table.tableVersion)) < 0) { + return ret; + } + AttributeRecordPtr attrPtr; + attrPtr.i = tablePtr.p->firstAttribute; + while (attrPtr.i != RNIL) { + c_attributeRecordPool.getPtr(attrPtr); + if (attrPtr.p->attributeId == attributeId) + break; + attrPtr.i = attrPtr.p->nextAttrInTable; + } + if (attrPtr.i == RNIL) { + return MetaData::AttributeNotFound; + } + new (&attr) MetaData::Attribute(*attrPtr.p); + return 0; +} + +int +Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table, const char* attributeName) +{ + int ret; + TableRecordPtr tablePtr; + if ((ret = getMetaTablePtr(tablePtr, table.tableId, table.tableVersion)) < 0) { + return ret; + } + AttributeRecordPtr attrPtr; + attrPtr.i = tablePtr.p->firstAttribute; + while (attrPtr.i != RNIL) { + c_attributeRecordPool.getPtr(attrPtr); + if (strcmp(attrPtr.p->attributeName, attributeName) == 0) + break; + attrPtr.i = attrPtr.p->nextAttrInTable; + } + if (attrPtr.i == RNIL) { + return MetaData::AttributeNotFound; + } + new (&attr) MetaData::Attribute(*attrPtr.p); + return 0; +} |