/* 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_DEBUG_CPP #include "Dbtux.hpp" /* * 12001 log file 0-close 1-open 2-append 3-append to signal log * 12002 log flags 1-meta 2-maint 4-tree 8-scan */ void Dbtux::execDUMP_STATE_ORD(Signal* signal) { jamEntry(); #ifdef VM_TRACE if (signal->theData[0] == DumpStateOrd::TuxLogToFile) { unsigned flag = signal->theData[1]; const char* const tuxlog = "tux.log"; FILE* slFile = globalSignalLoggers.getOutputStream(); if (flag <= 3) { if (debugFile != 0) { if (debugFile != slFile) fclose(debugFile); debugFile = 0; debugOut = *new NdbOut(*new NullOutputStream()); } if (flag == 1) debugFile = fopen(tuxlog, "w"); if (flag == 2) debugFile = fopen(tuxlog, "a"); if (flag == 3) debugFile = slFile; if (debugFile != 0) debugOut = *new NdbOut(*new FileOutputStream(debugFile)); } return; } if (signal->theData[0] == DumpStateOrd::TuxSetLogFlags) { debugFlags = signal->theData[1]; return; } if (signal->theData[0] == DumpStateOrd::TuxMetaDataJunk) { // read table definition Uint32 tableId = signal->theData[1]; Uint32 tableVersion = signal->theData[2]; int ret; MetaData md(this); MetaData::Table table; MetaData::Attribute attribute; infoEvent("md: read table %u %u", tableId, tableVersion); if ((ret = md.lock(false)) < 0) { infoEvent("md.lock error %d", ret); return; } if ((ret = md.getTable(table, tableId, tableVersion)) < 0) { infoEvent("md.getTable error %d", ret); // lock is released by destructor return; } infoEvent("md: %s type=%d attrs=%u", table.tableName, table.tableType, table.noOfAttributes); for (Uint32 i = 0; i < table.noOfAttributes; i++) { if ((ret = md.getAttribute(attribute, table, i)) < 0) { infoEvent("mg.getAttribute %u error %d", i, ret); // lock is released by destructor return; } infoEvent("md: %d %s", attribute.attributeId, attribute.attributeName); } if ((ret = md.unlock(false)) < 0) { infoEvent("md.unlock error %d", ret); return; } return; } #endif } #ifdef VM_TRACE void Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out) { TreeHead& tree = frag.m_tree; PrintPar par; strcpy(par.m_path, "."); par.m_side = 2; par.m_parent = NullTupLoc; printNode(signal, frag, out, tree.m_root, par); out.m_out->flush(); if (! par.m_ok) { if (debugFile == 0) { signal->theData[0] = 12001; signal->theData[1] = 1; execDUMP_STATE_ORD(signal); if (debugFile != 0) { printTree(signal, frag, debugOut); } } ndbrequire(false); } } void Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par) { if (loc == NullTupLoc) { par.m_depth = 0; return; } TreeHead& tree = frag.m_tree; NodeHandle node(frag); selectNode(signal, node, loc, AccFull); out << par.m_path << " " << node << endl; // check children PrintPar cpar[2]; ndbrequire(strlen(par.m_path) + 1 < sizeof(par.m_path)); for (unsigned i = 0; i <= 1; i++) { sprintf(cpar[i].m_path, "%s%c", par.m_path, "LR"[i]); cpar[i].m_side = i; cpar[i].m_depth = 0; cpar[i].m_parent = loc; printNode(signal, frag, out, node.getLink(i), cpar[i]); if (! cpar[i].m_ok) { par.m_ok = false; } } static const char* const sep = " *** "; // check child-parent links if (node.getLink(2) != par.m_parent) { par.m_ok = false; out << par.m_path << sep; out << "parent loc " << hex << node.getLink(2); out << " should be " << hex << par.m_parent << endl; } if (node.getSide() != par.m_side) { par.m_ok = false; out << par.m_path << sep; out << "side " << dec << node.getSide(); out << " should be " << dec << par.m_side << endl; } // check balance const int balance = -cpar[0].m_depth + cpar[1].m_depth; if (node.getBalance() != balance) { par.m_ok = false; out << par.m_path << sep; out << "balance " << node.getBalance(); out << " should be " << balance << endl; } if (abs(node.getBalance()) > 1) { par.m_ok = false; out << par.m_path << sep; out << "balance " << node.getBalance() << " is invalid" << endl; } // check occupancy if (node.getOccup() == 0 || node.getOccup() > tree.m_maxOccup) { par.m_ok = false; out << par.m_path << sep; out << "occupancy " << node.getOccup(); out << " zero or greater than max " << tree.m_maxOccup << endl; } // check for occupancy of interior node if (node.getChilds() == 2 && node.getOccup() < tree.m_minOccup) { par.m_ok = false; out << par.m_path << sep; out << "occupancy " << node.getOccup() << " of interior node"; out << " less than min " << tree.m_minOccup << endl; } // check missed half-leaf/leaf merge for (unsigned i = 0; i <= 1; i++) { if (node.getLink(i) != NullTupLoc && node.getLink(1 - i) == NullTupLoc && node.getOccup() + cpar[i].m_occup <= tree.m_maxOccup) { par.m_ok = false; out << par.m_path << sep; out << "missed merge with child " << i << endl; } } // check inline prefix { ConstData data1 = node.getPref(); Uint32 data2[MaxPrefSize]; memset(data2, DataFillByte, MaxPrefSize << 2); readKeyAttrs(frag, node.getMinMax(0), 0, c_searchKey); copyAttrs(frag, c_searchKey, data2, tree.m_prefSize); for (unsigned n = 0; n < tree.m_prefSize; n++) { if (data1[n] != data2[n]) { par.m_ok = false; out << par.m_path << sep; out << "inline prefix mismatch word " << n; out << " value " << hex << data1[n]; out << " should be " << hex << data2[n] << endl; break; } } } // check ordering within node for (unsigned j = 1; j < node.getOccup(); j++) { const TreeEnt ent1 = node.getEnt(j - 1); const TreeEnt ent2 = node.getEnt(j); unsigned start = 0; readKeyAttrs(frag, ent1, start, c_searchKey); readKeyAttrs(frag, ent2, start, c_entryKey); int ret = cmpSearchKey(frag, start, c_searchKey, c_entryKey); if (ret == 0) ret = ent1.cmp(ent2); if (ret != -1) { par.m_ok = false; out << par.m_path << sep; out << " disorder within node at pos " << j << endl; } } // check ordering wrt subtrees for (unsigned i = 0; i <= 1; i++) { if (node.getLink(i) == NullTupLoc) continue; const TreeEnt ent1 = cpar[i].m_minmax[1 - i]; const TreeEnt ent2 = node.getMinMax(i); unsigned start = 0; readKeyAttrs(frag, ent1, start, c_searchKey); readKeyAttrs(frag, ent2, start, c_entryKey); int ret = cmpSearchKey(frag, start, c_searchKey, c_entryKey); if (ret == 0) ret = ent1.cmp(ent2); if (ret != (i == 0 ? -1 : +1)) { par.m_ok = false; out << par.m_path << sep; out << " disorder wrt subtree " << i << endl; } } // return values par.m_depth = 1 + max(cpar[0].m_depth, cpar[1].m_depth); par.m_occup = node.getOccup(); for (unsigned i = 0; i <= 1; i++) { if (node.getLink(i) == NullTupLoc) par.m_minmax[i] = node.getMinMax(i); else par.m_minmax[i] = cpar[i].m_minmax[i]; } } NdbOut& operator<<(NdbOut& out, const Dbtux::TupLoc& loc) { if (loc == Dbtux::NullTupLoc) { out << "null"; } else { out << dec << loc.getPageId(); out << "." << dec << loc.getPageOffset(); } return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::TreeEnt& ent) { out << dec << ent.m_fragBit; out << "-" << ent.m_tupLoc; out << "-" << dec << ent.m_tupVersion; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::TreeNode& node) { out << "[TreeNode " << hex << &node; out << " [left " << node.m_link[0] << "]"; out << " [right " << node.m_link[1] << "]"; out << " [up " << node.m_link[2] << "]"; out << " [side " << dec << node.m_side << "]"; out << " [occup " << dec << node.m_occup << "]"; out << " [balance " << dec << (int)node.m_balance << "]"; out << " [nodeScan " << hex << node.m_nodeScan << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::TreeHead& tree) { out << "[TreeHead " << hex << &tree; out << " [nodeSize " << dec << tree.m_nodeSize << "]"; out << " [prefSize " << dec << tree.m_prefSize << "]"; out << " [minOccup " << dec << tree.m_minOccup << "]"; out << " [maxOccup " << dec << tree.m_maxOccup << "]"; out << " [AccHead " << dec << tree.getSize(Dbtux::AccHead) << "]"; out << " [AccPref " << dec << tree.getSize(Dbtux::AccPref) << "]"; out << " [AccFull " << dec << tree.getSize(Dbtux::AccFull) << "]"; out << " [root " << hex << tree.m_root << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::TreePos& pos) { out << "[TreePos " << hex << &pos; out << " [loc " << pos.m_loc << "]"; out << " [pos " << dec << pos.m_pos << "]"; out << " [match " << dec << pos.m_match << "]"; out << " [dir " << dec << pos.m_dir << "]"; out << " [ent " << pos.m_ent << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::DescAttr& descAttr) { out << "[DescAttr " << hex << &descAttr; out << " [attrDesc " << hex << descAttr.m_attrDesc; out << " [primaryAttrId " << dec << descAttr.m_primaryAttrId << "]"; out << " [typeId " << dec << descAttr.m_typeId << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::ScanOp& scan) { out << "[ScanOp " << hex << &scan; out << " [state " << dec << scan.m_state << "]"; out << " [lockwait " << dec << scan.m_lockwait << "]"; out << " [indexId " << dec << scan.m_indexId << "]"; out << " [fragId " << dec << scan.m_fragId << "]"; out << " [transId " << hex << scan.m_transId1 << " " << scan.m_transId2 << "]"; out << " [savePointId " << dec << scan.m_savePointId << "]"; out << " [accLockOp " << hex << scan.m_accLockOp << "]"; out << " [accLockOps"; for (unsigned i = 0; i < Dbtux::MaxAccLockOps; i++) { if (scan.m_accLockOps[i] != RNIL) out << " " << hex << scan.m_accLockOps[i]; } out << "]"; out << " [readCommitted " << dec << scan.m_readCommitted << "]"; out << " [lockMode " << dec << scan.m_lockMode << "]"; out << " [keyInfo " << dec << scan.m_keyInfo << "]"; out << " [pos " << scan.m_scanPos << "]"; for (unsigned i = 0; i <= 1; i++) { out << " [bound " << dec << i; Dbtux::ScanBound& bound = *scan.m_bound[i]; Dbtux::ScanBoundIterator iter; bound.first(iter); for (unsigned j = 0; j < bound.getSize(); j++) { out << " " << hex << *iter.data; bound.next(iter); } out << "]"; } out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::Index& index) { out << "[Index " << hex << &index; out << " [tableId " << dec << index.m_tableId << "]"; out << " [fragOff " << dec << index.m_fragOff << "]"; out << " [numFrags " << dec << index.m_numFrags << "]"; for (unsigned i = 0; i < index.m_numFrags; i++) { out << " [frag " << dec << i << " "; // dangerous and wrong Dbtux* tux = (Dbtux*)globalData.getBlock(DBTUX); const Dbtux::Frag& frag = *tux->c_fragPool.getPtr(index.m_fragPtrI[i]); out << frag; out << "]"; } out << " [descPage " << hex << index.m_descPage << "]"; out << " [descOff " << dec << index.m_descOff << "]"; out << " [numAttrs " << dec << index.m_numAttrs << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::Frag& frag) { out << "[Frag " << hex << &frag; out << " [tableId " << dec << frag.m_tableId << "]"; out << " [indexId " << dec << frag.m_indexId << "]"; out << " [fragOff " << dec << frag.m_fragOff << "]"; out << " [fragId " << dec << frag.m_fragId << "]"; out << " [descPage " << hex << frag.m_descPage << "]"; out << " [descOff " << dec << frag.m_descOff << "]"; out << " [numAttrs " << dec << frag.m_numAttrs << "]"; out << " [tree " << frag.m_tree << "]"; out << "]"; return out; } NdbOut& operator<<(NdbOut& out, const Dbtux::NodeHandle& node) { const Dbtux::Frag& frag = node.m_frag; const Dbtux::TreeHead& tree = frag.m_tree; out << "[NodeHandle " << hex << &node; out << " [loc " << node.m_loc << "]"; out << " [acc " << dec << node.m_acc << "]"; out << " [node " << *node.m_node << "]"; if (node.m_acc >= Dbtux::AccPref) { const Uint32* data; out << " [pref"; data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize; for (unsigned j = 0; j < tree.m_prefSize; j++) out << " " << hex << data[j]; out << "]"; out << " [entList"; unsigned numpos = node.m_node->m_occup; if (node.m_acc < Dbtux::AccFull && numpos > 2) { numpos = 2; out << "(" << dec << numpos << ")"; } data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize; const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data; // print entries in logical order for (unsigned pos = 1; pos <= numpos; pos++) out << " " << entList[pos % numpos]; out << "]"; } out << "]"; return out; } #endif