diff options
Diffstat (limited to 'ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp')
-rw-r--r-- | ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp new file mode 100644 index 00000000000..a6b2485067c --- /dev/null +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp @@ -0,0 +1,369 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#define DBTUX_MAINT_CPP +#include "Dbtux.hpp" + +/* + * Maintain index. + */ + +void +Dbtux::execTUX_MAINT_REQ(Signal* signal) +{ + jamEntry(); + TuxMaintReq* const sig = (TuxMaintReq*)signal->getDataPtrSend(); + // ignore requests from redo log + if (c_internalStartPhase < 6 && + c_typeOfStart != NodeState::ST_NODE_RESTART && + c_typeOfStart != NodeState::ST_INITIAL_NODE_RESTART) { + jam(); +#ifdef VM_TRACE + if (debugFlags & DebugMaint) { + debugOut << "opInfo=" << hex << sig->opInfo; + debugOut << " tableId=" << dec << sig->tableId; + debugOut << " indexId=" << dec << sig->indexId; + debugOut << " fragId=" << dec << sig->fragId; + debugOut << " tupAddr=" << hex << sig->tupAddr; + debugOut << " tupVersion=" << dec << sig->tupVersion; + debugOut << " -- ignored at ISP=" << dec << c_internalStartPhase; + debugOut << " TOS=" << dec << c_typeOfStart; + debugOut << endl; + } +#endif + sig->errorCode = 0; + return; + } + TuxMaintReq reqCopy = *sig; + TuxMaintReq* const req = &reqCopy; + const Uint32 opCode = req->opInfo & 0xFF; + const Uint32 opFlag = req->opInfo >> 8; + // get the index + IndexPtr indexPtr; + c_indexPool.getPtr(indexPtr, req->indexId); + ndbrequire(indexPtr.p->m_tableId == req->tableId); + // get base fragment id and extra bits + const Uint32 fragOff = indexPtr.p->m_fragOff; + const Uint32 fragId = req->fragId & ((1 << fragOff) - 1); + const Uint32 fragBit = req->fragId >> fragOff; + // get the fragment + FragPtr fragPtr; + fragPtr.i = RNIL; + for (unsigned i = 0; i < indexPtr.p->m_numFrags; i++) { + jam(); + if (indexPtr.p->m_fragId[i] == fragId) { + jam(); + c_fragPool.getPtr(fragPtr, indexPtr.p->m_fragPtrI[i]); + break; + } + } + ndbrequire(fragPtr.i != RNIL); + Frag& frag = *fragPtr.p; + ndbrequire(frag.m_nodeList == RNIL); + // set up index entry + TreeEnt ent; + ent.m_tupAddr = req->tupAddr; + ent.m_tupVersion = req->tupVersion; + ent.m_fragBit = fragBit; + // read search key + ReadPar readPar; + readPar.m_ent = ent; + readPar.m_first = 0; + readPar.m_count = frag.m_numAttrs; + // output goes here + readPar.m_data = c_keyBuffer; + tupReadAttrs(signal, frag, readPar); + // check if all keys are null + { + bool allNull = true; + ConstData data = readPar.m_data; + for (unsigned i = 0; i < frag.m_numAttrs; i++) { + if (! data.ah().isNULL()) { + jam(); + allNull = false; + break; + } + data += AttributeHeaderSize + data.ah().getDataSize(); + } + if (allNull) { + jam(); + req->errorCode = 0; + *sig = *req; + return; + } + } + // find position in tree + SearchPar searchPar; + searchPar.m_data = c_keyBuffer; + searchPar.m_ent = ent; + TreePos treePos; +#ifdef VM_TRACE + if (debugFlags & DebugMaint) { + debugOut << "opCode=" << dec << opCode; + debugOut << " opFlag=" << dec << opFlag; + debugOut << " tableId=" << dec << req->tableId; + debugOut << " indexId=" << dec << req->indexId; + debugOut << " fragId=" << dec << req->fragId; + debugOut << " entry=" << ent; + debugOut << endl; + } +#endif + treeSearch(signal, frag, searchPar, treePos); +#ifdef VM_TRACE + if (debugFlags & DebugMaint) { + debugOut << treePos << endl; + } +#endif + // do the operation + req->errorCode = 0; + switch (opCode) { + case TuxMaintReq::OpAdd: + jam(); + if (treePos.m_match) { + jam(); + // there is no "Building" state so this will have to do + if (indexPtr.p->m_state == Index::Online) { + jam(); + req->errorCode = TuxMaintReq::SearchError; + } + break; + } + /* + * At most one new node is inserted in the operation. We keep one + * free node pre-allocated so the operation cannot fail. This also + * gives a real TupAddr for links to the new node. + */ + if (frag.m_nodeFree == RNIL) { + jam(); + preallocNode(signal, frag, req->errorCode); + if (req->errorCode != 0) { + jam(); + break; + } + ndbrequire(frag.m_nodeFree != RNIL); + } + treeAdd(signal, frag, treePos, ent); + break; + case TuxMaintReq::OpRemove: + jam(); + if (! treePos.m_match) { + jam(); + // there is no "Building" state so this will have to do + if (indexPtr.p->m_state == Index::Online) { + jam(); + req->errorCode = TuxMaintReq::SearchError; + } + break; + } + treeRemove(signal, frag, treePos); + break; + default: + ndbrequire(false); + break; + } + // commit and release nodes + commitNodes(signal, frag, req->errorCode == 0); +#ifdef VM_TRACE + if (debugFlags & DebugTree) { + printTree(signal, frag, debugOut); + } +#endif + // copy back + *sig = *req; +} + +/* + * Read index key attributes from TUP. If buffer is provided the data + * is copied to it. Otherwise pointer is set to signal data. + */ +void +Dbtux::tupReadAttrs(Signal* signal, const Frag& frag, ReadPar& readPar) +{ + // define the direct signal + const TreeEnt ent = readPar.m_ent; + TupReadAttrs* const req = (TupReadAttrs*)signal->getDataPtrSend(); + req->errorCode = RNIL; + req->requestInfo = 0; + req->tableId = frag.m_tableId; + req->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff); + req->fragPtrI = RNIL; + req->tupAddr = ent.m_tupAddr; + req->tupVersion = ent.m_tupVersion; + req->pageId = RNIL; + req->pageOffset = 0; + req->bufferId = 0; + // add count and list of attribute ids + Data data = (Uint32*)req + TupReadAttrs::SignalLength; + data[0] = readPar.m_count; + data += 1; + const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff); + for (Uint32 i = 0; i < readPar.m_count; i++) { + jam(); + const DescAttr& descAttr = descEnt.m_descAttr[readPar.m_first + i]; + data.ah() = AttributeHeader(descAttr.m_primaryAttrId, 0); + data += 1; + } + // execute + EXECUTE_DIRECT(DBTUP, GSN_TUP_READ_ATTRS, signal, TupReadAttrs::SignalLength); + jamEntry(); + ndbrequire(req->errorCode == 0); + // data is at output + if (readPar.m_data == 0) { + readPar.m_data = data; + } else { + jam(); + CopyPar copyPar; + copyPar.m_items = readPar.m_count; + copyPar.m_headers = true; + copyAttrs(readPar.m_data, data, copyPar); + } +} + +/* + * Read primary keys. Copy the data without attribute headers into the + * given buffer. Number of words is returned in ReadPar argument. + */ +void +Dbtux::tupReadKeys(Signal* signal, const Frag& frag, ReadPar& readPar) +{ + // define the direct signal + const TreeEnt ent = readPar.m_ent; + TupReadAttrs* const req = (TupReadAttrs*)signal->getDataPtrSend(); + req->errorCode = RNIL; + req->requestInfo = TupReadAttrs::ReadKeys; + req->tableId = frag.m_tableId; + req->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff); + req->fragPtrI = RNIL; + req->tupAddr = ent.m_tupAddr; + req->tupVersion = RNIL; // not used + req->pageId = RNIL; + req->pageOffset = 0; + req->bufferId = 0; + // execute + EXECUTE_DIRECT(DBTUP, GSN_TUP_READ_ATTRS, signal, TupReadAttrs::SignalLength); + jamEntry(); + ndbrequire(req->errorCode == 0); + // copy out in special format + ConstData data = (Uint32*)req + TupReadAttrs::SignalLength; + const Uint32 numKeys = data[0]; + data += 1 + numKeys; + // copy out without headers + ndbrequire(readPar.m_data != 0); + CopyPar copyPar; + copyPar.m_items = numKeys; + copyPar.m_headers = false; + copyAttrs(readPar.m_data, data, copyPar); + // return counts + readPar.m_count = numKeys; + readPar.m_size = copyPar.m_numwords; +} + +/* + * Operate on index node tuple in TUP. The data is copied between node + * cache and index storage via signal data. + */ +void +Dbtux::tupStoreTh(Signal* signal, const Frag& frag, NodeHandlePtr nodePtr, StorePar storePar) +{ + const TreeHead& tree = frag.m_tree; + // define the direct signal + TupStoreTh* req = (TupStoreTh*)signal->getDataPtrSend(); + req->errorCode = RNIL; + req->tableId = frag.m_indexId; + req->fragId = frag.m_fragId; + req->fragPtrI = RNIL; + req->tupAddr = nodePtr.p->m_addr; + req->tupVersion = 0; + req->pageId = nodePtr.p->m_loc.m_pageId; + req->pageOffset = nodePtr.p->m_loc.m_pageOffset; + req->bufferId = 0; + req->opCode = storePar.m_opCode; + ndbrequire(storePar.m_offset + storePar.m_size <= tree.m_nodeSize); + req->dataOffset = storePar.m_offset; + req->dataSize = storePar.m_size; + // the node cache + ndbrequire(nodePtr.p->m_node != 0); + // the buffer in signal data + Uint32* const buffer = (Uint32*)req + TupStoreTh::SignalLength; + // copy in data + switch (storePar.m_opCode) { + case TupStoreTh::OpRead: + jam(); + #ifdef VM_TRACE + { + Uint32* dst = buffer + storePar.m_offset; + memset(dst, 0xa9, storePar.m_size << 2); + } + #endif + break; + case TupStoreTh::OpInsert: + jam(); + // fallthru + case TupStoreTh::OpUpdate: + jam(); + // copy from cache to signal data + { + Uint32* dst = buffer + storePar.m_offset; + const Uint32* src = (const Uint32*)nodePtr.p->m_node + storePar.m_offset; + memcpy(dst, src, storePar.m_size << 2); + } + break; + case TupStoreTh::OpDelete: + jam(); + break; + default: + ndbrequire(false); + break; + } + // execute + EXECUTE_DIRECT(DBTUP, GSN_TUP_STORE_TH, signal, TupStoreTh::SignalLength); + jamEntry(); + if (req->errorCode != 0) { + jam(); + storePar.m_errorCode = req->errorCode; + return; + } + ndbrequire(req->errorCode == 0); + // copy out data + switch (storePar.m_opCode) { + case TupStoreTh::OpRead: + jam(); + { + Uint32* dst = (Uint32*)nodePtr.p->m_node + storePar.m_offset; + const Uint32* src = (const Uint32*)buffer + storePar.m_offset; + memcpy(dst, src, storePar.m_size << 2); + } + // fallthru + case TupStoreTh::OpInsert: + jam(); + // fallthru + case TupStoreTh::OpUpdate: + jam(); + nodePtr.p->m_addr = req->tupAddr; + nodePtr.p->m_loc.m_pageId = req->pageId; + nodePtr.p->m_loc.m_pageOffset = req->pageOffset; + break; + case TupStoreTh::OpDelete: + jam(); + nodePtr.p->m_addr = NullTupAddr; + nodePtr.p->m_loc.m_pageId = RNIL; + nodePtr.p->m_loc.m_pageOffset = 0; + break; + default: + ndbrequire(false); + break; + } +} |