/* * Set prefix. Copies the defined number of attributes. */ void Dbtux::setNodePref(TuxCtx & ctx, NodeHandle& node) { const Frag& frag = node.m_frag; const Index& index = *c_indexPool.getPtr(frag.m_indexId); /* * bug#12873640 * Node prefix exists if it has non-zero number of attributes. It is * then a partial instance of KeyData. If the prefix does not exist * then set_buf() could overwrite m_pageId1 in first entry, causing * random crash in TUP via readKeyAttrs(). */ if (index.m_prefAttrs > 0) { KeyData prefKey(index.m_keySpec, false, 0); prefKey.set_buf(node.getPref(), index.m_prefBytes); thrjam(ctx.jamBuffer); readKeyAttrs(ctx, frag, node.getEnt(0), prefKey, index.m_prefAttrs); #ifdef VM_TRACE if (debugFlags & DebugMaint) { debugOut << "setNodePref: " << node; debugOut << " " << prefKey.print(ctx.c_debugBuffer, DebugBufferBytes); debugOut << endl; } #endif } }
/* * Set prefix. Copies the number of words that fits. Includes * attribute headers for now. XXX use null mask instead */ void Dbtux::setNodePref(NodeHandle& node) { const Frag& frag = node.m_frag; const TreeHead& tree = frag.m_tree; readKeyAttrs(frag, node.getMinMax(0), 0, c_entryKey); copyAttrs(frag, c_entryKey, node.getPref(), tree.m_prefSize); }
void Dbtux::execTUX_MAINT_REQ(Signal* signal) { jamEntry(); TuxMaintReq* const sig = (TuxMaintReq*)signal->getDataPtrSend(); // ignore requests from redo log IndexPtr indexPtr; c_indexPool.getPtr(indexPtr, sig->indexId); if (unlikely(! (indexPtr.p->m_state == Index::Online || indexPtr.p->m_state == Index::Building))) { jam(); #ifdef VM_TRACE if (debugFlags & DebugMaint) { TupLoc tupLoc(sig->pageId, sig->pageIndex); debugOut << "opInfo=" << hex << sig->opInfo; debugOut << " tableId=" << dec << sig->tableId; debugOut << " indexId=" << dec << sig->indexId; debugOut << " fragId=" << dec << sig->fragId; debugOut << " tupLoc=" << tupLoc; 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; // get the index ndbrequire(indexPtr.p->m_tableId == req->tableId); // get base fragment id and extra bits const Uint32 fragId = req->fragId; // get the fragment FragPtr fragPtr; findFrag(jamBuffer(), *indexPtr.p, fragId, fragPtr); ndbrequire(fragPtr.i != RNIL); Frag& frag = *fragPtr.p; // set up search entry TreeEnt ent; ent.m_tupLoc = TupLoc(req->pageId, req->pageIndex); ent.m_tupVersion = req->tupVersion; // set up and read search key KeyData searchKey(indexPtr.p->m_keySpec, false, 0); searchKey.set_buf(c_ctx.c_searchKey, MaxAttrDataSize << 2); readKeyAttrs(c_ctx, frag, ent, searchKey, indexPtr.p->m_numAttrs); if (unlikely(! indexPtr.p->m_storeNullKey) && searchKey.get_null_cnt() == indexPtr.p->m_numAttrs) { jam(); return; } #ifdef VM_TRACE if (debugFlags & DebugMaint) { const Uint32 opFlag = req->opInfo >> 8; 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 // do the operation req->errorCode = 0; TreePos treePos; bool ok; switch (opCode) { case TuxMaintReq::OpAdd: jam(); ok = searchToAdd(c_ctx, frag, searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { debugOut << treePos << (! ok ? " - error" : "") << endl; } #endif if (! ok) { 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. Pre-allocate * it so that the operation cannot fail. */ if (frag.m_freeLoc == NullTupLoc) { jam(); NodeHandle node(frag); req->errorCode = allocNode(c_ctx, node); if (req->errorCode != 0) { jam(); break; } frag.m_freeLoc = node.m_loc; ndbrequire(frag.m_freeLoc != NullTupLoc); } treeAdd(c_ctx, frag, treePos, ent); frag.m_entryCount++; frag.m_entryBytes += searchKey.get_data_len(); frag.m_entryOps++; break; case TuxMaintReq::OpRemove: jam(); ok = searchToRemove(c_ctx, frag, searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { debugOut << treePos << (! ok ? " - error" : "") << endl; } #endif if (! ok) { 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(frag, treePos); ndbrequire(frag.m_entryCount != 0); frag.m_entryCount--; frag.m_entryBytes -= searchKey.get_data_len(); frag.m_entryOps++; break; default: ndbrequire(false); break; } #ifdef VM_TRACE if (debugFlags & DebugTree) { printTree(signal, frag, debugOut); } #endif // copy back *sig = *req; //ndbrequire(c_keyAttrs[0] == c_keyAttrs[1]); //ndbrequire(c_sqlCmp[0] == c_sqlCmp[1]); //ndbrequire(c_searchKey[0] == c_searchKey[1]); //ndbrequire(c_entryKey[0] == c_entryKey[1]); //ndbrequire(c_dataBuffer[0] == c_dataBuffer[1]); }
void Dbtux::searchToScanDescending(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos) { const TreeHead& tree = frag.m_tree; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; NodeHandle glbNode(frag); // potential g.l.b of final node NodeHandle bottomNode(frag); while (true) { jam(); selectNode(currNode, currNode.m_loc); int ret; // compare prefix ret = cmpScanBound(frag, 1, boundInfo, boundCount, currNode.getPref(), tree.m_prefSize); if (ret == NdbSqlUtil::CmpUnknown) { jam(); // read and compare all attributes readKeyAttrs(frag, currNode.getMinMax(0), 0, c_entryKey); ret = cmpScanBound(frag, 1, boundInfo, boundCount, c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); } if (ret < 0) { // bound is left of this node jam(); const TupLoc loc = currNode.getLink(0); if (loc != NullTupLoc) { jam(); // continue to left subtree currNode.m_loc = loc; continue; } if (! glbNode.isNull()) { jam(); // move up to the g.l.b but remember the bottom node bottomNode = currNode; currNode = glbNode; } else { // empty result set return; } } else { // bound is at or right of this node jam(); const TupLoc loc = currNode.getLink(1); if (loc != NullTupLoc) { jam(); // save potential g.l.b glbNode = currNode; // continue to right subtree currNode.m_loc = loc; continue; } } break; } for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) { jam(); int ret; // read and compare attributes readKeyAttrs(frag, currNode.getEnt(j), 0, c_entryKey); ret = cmpScanBound(frag, 1, boundInfo, boundCount, c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); if (ret < 0) { if (j > 0) { // start scanning from previous entry treePos.m_loc = currNode.m_loc; treePos.m_pos = j - 1; treePos.m_dir = 3; return; } // start scanning upwards (pretend we came from left child) treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; treePos.m_dir = 0; return; } } // start scanning this node treePos.m_loc = currNode.m_loc; treePos.m_pos = currNode.getOccup() - 1; treePos.m_dir = 3; }
/* * Search for entry to add. * * Similar to searchToRemove (see below). */ bool Dbtux::searchToAdd(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) { const TreeHead& tree = frag.m_tree; const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; if (currNode.m_loc == NullTupLoc) { // empty tree jam(); return true; } NodeHandle glbNode(frag); // potential g.l.b of final node /* * In order to not (yet) change old behaviour, a position between * 2 nodes returns the one at the bottom of the tree. */ NodeHandle bottomNode(frag); while (true) { jam(); selectNode(currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; ret = cmpSearchKey(frag, start, searchKey, currNode.getPref(), tree.m_prefSize); if (ret == NdbSqlUtil::CmpUnknown) { jam(); // read and compare remaining attributes ndbrequire(start < numAttrs); readKeyAttrs(frag, currNode.getMinMax(0), start, c_entryKey); ret = cmpSearchKey(frag, start, searchKey, c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); } if (ret == 0) { jam(); // keys are equal, compare entry values ret = searchEnt.cmp(currNode.getMinMax(0)); } if (ret < 0) { jam(); const TupLoc loc = currNode.getLink(0); if (loc != NullTupLoc) { jam(); // continue to left subtree currNode.m_loc = loc; continue; } if (! glbNode.isNull()) { jam(); // move up to the g.l.b but remember the bottom node bottomNode = currNode; currNode = glbNode; } } else if (ret > 0) { jam(); const TupLoc loc = currNode.getLink(1); if (loc != NullTupLoc) { jam(); // save potential g.l.b glbNode = currNode; // continue to right subtree currNode.m_loc = loc; continue; } } else { jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; // entry found - error return false; } break; } // anticipate treePos.m_loc = currNode.m_loc; // binary search int lo = -1; int hi = currNode.getOccup(); int ret; while (1) { jam(); // hi - lo > 1 implies lo < j < hi int j = (hi + lo) / 2; // read and compare attributes unsigned start = 0; readKeyAttrs(frag, currNode.getEnt(j), start, c_entryKey); ret = cmpSearchKey(frag, start, searchKey, c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); if (ret == 0) { jam(); // keys are equal, compare entry values ret = searchEnt.cmp(currNode.getEnt(j)); } if (ret < 0) hi = j; else if (ret > 0) lo = j; else { treePos.m_pos = j; // entry found - error return false; } if (hi - lo == 1) break; } if (ret < 0) { jam(); treePos.m_pos = hi; return true; } if ((uint) hi < currNode.getOccup()) { jam(); treePos.m_pos = hi; return true; } if (bottomNode.isNull()) { jam(); treePos.m_pos = hi; return true; } jam(); // backwards compatible for now treePos.m_loc = bottomNode.m_loc; treePos.m_pos = 0; return true; }
/* * Search for entry to remove. * * Compares search key to each node min. A move to right subtree can * overshoot target node. The last such node is saved. The final node * is a semi-leaf or leaf. If search key is less than final node min * then the saved node is the g.l.b of the final node and we move back * to it. */ bool Dbtux::searchToRemove(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) { const TreeHead& tree = frag.m_tree; const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; if (currNode.m_loc == NullTupLoc) { // empty tree - failed jam(); return false; } NodeHandle glbNode(frag); // potential g.l.b of final node while (true) { jam(); selectNode(currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; ret = cmpSearchKey(frag, start, searchKey, currNode.getPref(), tree.m_prefSize); if (ret == NdbSqlUtil::CmpUnknown) { jam(); // read and compare remaining attributes ndbrequire(start < numAttrs); readKeyAttrs(frag, currNode.getMinMax(0), start, c_entryKey); ret = cmpSearchKey(frag, start, searchKey, c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); } if (ret == 0) { jam(); // keys are equal, compare entry values ret = searchEnt.cmp(currNode.getMinMax(0)); } if (ret < 0) { jam(); const TupLoc loc = currNode.getLink(0); if (loc != NullTupLoc) { jam(); // continue to left subtree currNode.m_loc = loc; continue; } if (! glbNode.isNull()) { jam(); // move up to the g.l.b currNode = glbNode; } } else if (ret > 0) { jam(); const TupLoc loc = currNode.getLink(1); if (loc != NullTupLoc) { jam(); // save potential g.l.b glbNode = currNode; // continue to right subtree currNode.m_loc = loc; continue; } } else { jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; return true; } break; } // anticipate treePos.m_loc = currNode.m_loc; // pos 0 was handled above for (unsigned j = 1, occup = currNode.getOccup(); j < occup; j++) { jam(); // compare only the entry if (searchEnt.eq(currNode.getEnt(j))) { jam(); treePos.m_pos = j; return true; } } treePos.m_pos = currNode.getOccup(); // not found - failed return false; }
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) { TupLoc tupLoc(sig->pageId, sig->pageOffset); debugOut << "opInfo=" << hex << sig->opInfo; debugOut << " tableId=" << dec << sig->tableId; debugOut << " indexId=" << dec << sig->indexId; debugOut << " fragId=" << dec << sig->fragId; debugOut << " tupLoc=" << tupLoc; 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 fragId = req->fragId & ~1; const Uint32 fragBit = req->fragId & 1; // 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; // set up index keys for this operation setKeyAttrs(frag); // set up search entry TreeEnt ent; ent.m_tupLoc = TupLoc(req->pageId, req->pageOffset); ent.m_tupVersion = req->tupVersion; ent.m_fragBit = fragBit; // read search key readKeyAttrs(frag, ent, 0, c_searchKey); if (! frag.m_storeNullKey) { // check if all keys are null const unsigned numAttrs = frag.m_numAttrs; bool allNull = true; for (unsigned i = 0; i < numAttrs; i++) { if (c_searchKey[i] != 0) { jam(); allNull = false; break; } } if (allNull) { jam(); req->errorCode = 0; *sig = *req; return; } } #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 // do the operation req->errorCode = 0; TreePos treePos; bool ok; switch (opCode) { case TuxMaintReq::OpAdd: jam(); ok = searchToAdd(frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { debugOut << treePos << (! ok ? " - error" : "") << endl; } #endif if (! ok) { 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. Pre-allocate * it so that the operation cannot fail. */ if (frag.m_freeLoc == NullTupLoc) { jam(); NodeHandle node(frag); req->errorCode = allocNode(signal, node); if (req->errorCode != 0) { jam(); break; } // link to freelist node.setLink(0, frag.m_freeLoc); frag.m_freeLoc = node.m_loc; ndbrequire(frag.m_freeLoc != NullTupLoc); } treeAdd(frag, treePos, ent); break; case TuxMaintReq::OpRemove: jam(); ok = searchToRemove(frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { debugOut << treePos << (! ok ? " - error" : "") << endl; } #endif if (! ok) { 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(frag, treePos); break; default: ndbrequire(false); break; } #ifdef VM_TRACE if (debugFlags & DebugTree) { printTree(signal, frag, debugOut); } #endif // copy back *sig = *req; }