/* 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.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 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(); // forward to DICT master sendSignal(calcDictBlockRef(c_masterNodeId), GSN_CREATE_INDX_REQ, signal, signal->getLength(), JBB); 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 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; } // hash index attributes must currently be in table order Uint32 prevAttrId = RNIL; for (k = 0; k < opPtr.p->m_attrList.sz; k++) { jam(); bool found = false; for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) { AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); tAttr = aRec->nextAttrInTable; if (aRec->attributeId != opPtr.p->m_attrList.id[k]) continue; jam(); found = true; const Uint32 a = aRec->attributeDescriptor; if (indexPtr.p->isHashIndex()) { const Uint32 s1 = AttributeDescriptor::getSize(a); const Uint32 s2 = AttributeDescriptor::getArraySize(a); indexPtr.p->tupKeyLength += ((1 << s1) * s2 + 31) >> 5; } } if (! found) { jam(); opPtr.p->m_errorCode = CreateIndxRef::BadRequestType; opPtr.p->m_errorLine = __LINE__; return; } if (indexPtr.p->isHashIndex() && k > 0 && prevAttrId >= opPtr.p->m_attrList.id[k]) { jam(); opPtr.p->m_errorCode = CreateIndxRef::InvalidAttributeOrder; opPtr.p->m_errorLine = __LINE__; return; } prevAttrId = opPtr.p->m_attrList.id[k]; } 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++) { jam(); for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) { AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr); tAttr = aRec->nextAttrInTable; if (aRec->attributeId != opPtr.p->m_attrList.id[k]) 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(); // forward to DICT master sendSignal(calcDictBlockRef(c_masterNodeId), GSN_DROP_INDX_REQ, signal, signal->getLength(), JBB); return; } // 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__; 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(); // forward to DICT master sendSignal(calcDictBlockRef(c_masterNodeId), GSN_ALTER_INDX_REQ, signal, signal->getLength(), JBB); 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(); // forward to DICT master sendSignal(calcDictBlockRef(c_masterNodeId), GSN_BUILDINDXREQ, signal, signal->getLength(), JBB); 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); 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(); // forward to DICT master sendSignal(calcDictBlockRef(c_masterNodeId), GSN_CREATE_TRIG_REQ, signal, signal->getLength(), JBB); 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; }