MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtuxDebug.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #define DBTUX_DEBUG_CPP
19 #include "Dbtux.hpp"
20 
21 #include <signaldata/DbinfoScan.hpp>
22 #include <signaldata/TransIdAI.hpp>
23 
24 
25 void Dbtux::execDBINFO_SCANREQ(Signal *signal)
26 {
27  DbinfoScanReq req= *(DbinfoScanReq*)signal->theData;
29  CAST_CONSTPTR(Ndbinfo::ScanCursor, DbinfoScan::getCursorPtr(&req));
31 
32  jamEntry();
33 
34  switch(req.tableId){
35  case Ndbinfo::POOLS_TABLEID:
36  {
37  Ndbinfo::pool_entry pools[] =
38  {
39  { "Index",
40  c_indexPool.getUsed(),
41  c_indexPool.getSize(),
42  c_indexPool.getEntrySize(),
43  c_indexPool.getUsedHi(),
44  { CFG_DB_NO_TABLES,
45  CFG_DB_NO_ORDERED_INDEXES,
46  CFG_DB_NO_UNIQUE_HASH_INDEXES,0 }},
47  { "Fragment",
48  c_fragPool.getUsed(),
49  c_fragPool.getSize(),
50  c_fragPool.getEntrySize(),
51  c_fragPool.getUsedHi(),
52  { CFG_DB_NO_ORDERED_INDEXES,
53  CFG_DB_NO_REPLICAS,0,0 }},
54  { "Descriptor page",
55  c_descPagePool.getUsed(),
56  c_descPagePool.getSize(),
57  c_descPagePool.getEntrySize(),
58  c_descPagePool.getUsedHi(),
59  { CFG_DB_NO_TABLES,
60  CFG_DB_NO_ORDERED_INDEXES,
61  CFG_DB_NO_UNIQUE_HASH_INDEXES,0 }},
62  { "Fragment Operation",
63  c_fragOpPool.getUsed(),
64  c_fragOpPool.getSize(),
65  c_fragOpPool.getEntrySize(),
66  c_fragOpPool.getUsedHi(),
67  { 0,0,0,0 }},
68  { "Scan Operation",
69  c_scanOpPool.getUsed(),
70  c_scanOpPool.getSize(),
71  c_scanOpPool.getEntrySize(),
72  c_scanOpPool.getUsedHi(),
73  { CFG_DB_NO_LOCAL_SCANS,0,0,0 }},
74  { "Scan Bound",
75  c_scanBoundPool.getUsed(),
76  c_scanBoundPool.getSize(),
77  c_scanBoundPool.getEntrySize(),
78  c_scanBoundPool.getUsedHi(),
79  { CFG_DB_NO_LOCAL_SCANS,0,0,0 }},
80  { "Scan Lock",
81  c_scanLockPool.getUsed(),
82  c_scanLockPool.getSize(),
83  c_scanLockPool.getEntrySize(),
84  c_scanLockPool.getUsedHi(),
85  { CFG_DB_NO_LOCAL_SCANS,
86  CFG_DB_BATCH_SIZE,0,0 }},
87  { NULL, 0,0,0,0,{ 0,0,0,0 }}
88  };
89 
90  const size_t num_config_params =
91  sizeof(pools[0].config_params) / sizeof(pools[0].config_params[0]);
92  Uint32 pool = cursor->data[0];
93  BlockNumber bn = blockToMain(number());
94  while(pools[pool].poolname)
95  {
96  jam();
97  Ndbinfo::Row row(signal, req);
98  row.write_uint32(getOwnNodeId());
99  row.write_uint32(bn); // block number
100  row.write_uint32(instance()); // block instance
101  row.write_string(pools[pool].poolname);
102  row.write_uint64(pools[pool].used);
103  row.write_uint64(pools[pool].total);
104  row.write_uint64(pools[pool].used_hi);
105  row.write_uint64(pools[pool].entry_size);
106  for (size_t i = 0; i < num_config_params; i++)
107  row.write_uint32(pools[pool].config_params[i]);
108  ndbinfo_send_row(signal, req, row, rl);
109  pool++;
110  if (rl.need_break(req))
111  {
112  jam();
113  ndbinfo_send_scan_break(signal, req, rl, pool);
114  return;
115  }
116  }
117  break;
118  }
119  default:
120  break;
121  }
122 
123  ndbinfo_send_scan_conf(signal, req, rl);
124 }
125 
126 /*
127  * 12001 log file 0-close 1-open 2-append 3-append to signal log
128  * 12002 log flags 1-meta 2-maint 4-tree 8-scan lock-16 stat-32
129  */
130 void
131 Dbtux::execDUMP_STATE_ORD(Signal* signal)
132 {
133  jamEntry();
134 #ifdef VM_TRACE
135  if (signal->theData[0] == DumpStateOrd::TuxLogToFile) {
136  unsigned flag = signal->theData[1];
137  const char* const tuxlog = "tux.log";
138  FILE* slFile = globalSignalLoggers.getOutputStream();
139  if (flag <= 3) {
140  if (debugFile != 0) {
141  if (debugFile != slFile)
142  fclose(debugFile);
143  debugFile = 0;
144  debugOut = *new NdbOut(*new NullOutputStream());
145  }
146  if (flag == 1)
147  debugFile = fopen(tuxlog, "w");
148  if (flag == 2)
149  debugFile = fopen(tuxlog, "a");
150  if (flag == 3)
151  debugFile = slFile;
152  if (debugFile != 0)
153  debugOut = *new NdbOut(*new FileOutputStream(debugFile));
154  }
155  return;
156  }
157  if (signal->theData[0] == DumpStateOrd::TuxSetLogFlags) {
158  debugFlags = signal->theData[1];
159  return;
160  }
161  if (signal->theData[0] == DumpStateOrd::TuxMetaDataJunk) {
162  abort();
163  }
164 #endif
165 
166  if (signal->theData[0] == DumpStateOrd::SchemaResourceSnapshot)
167  {
168  RSS_AP_SNAPSHOT_SAVE(c_indexPool);
169  RSS_AP_SNAPSHOT_SAVE(c_fragPool);
170  RSS_AP_SNAPSHOT_SAVE(c_fragOpPool);
171  }
172 
173  if (signal->theData[0] == DumpStateOrd::SchemaResourceCheckLeak)
174  {
175  RSS_AP_SNAPSHOT_CHECK(c_indexPool);
176  RSS_AP_SNAPSHOT_CHECK(c_fragPool);
177  RSS_AP_SNAPSHOT_CHECK(c_fragOpPool);
178  }
179 }
180 
181 #ifdef VM_TRACE
182 
183 void
184 Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out)
185 {
186  TreeHead& tree = frag.m_tree;
187  PrintPar par;
188  strcpy(par.m_path, ".");
189  par.m_side = 2;
190  par.m_parent = NullTupLoc;
191  printNode(c_ctx, frag, out, tree.m_root, par);
192  out.m_out->flush();
193  if (! par.m_ok) {
194  if (debugFile == 0) {
195  signal->theData[0] = 12001;
196  signal->theData[1] = 1;
197  execDUMP_STATE_ORD(signal);
198  if (debugFile != 0) {
199  printTree(signal, frag, debugOut);
200  }
201  }
202  ndbrequire(false);
203  }
204 }
205 
206 void
207 Dbtux::printNode(TuxCtx & ctx,
208  Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par)
209 {
210  if (loc == NullTupLoc) {
211  par.m_depth = 0;
212  return;
213  }
214  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
215  TreeHead& tree = frag.m_tree;
216  NodeHandle node(frag);
217  selectNode(node, loc);
218  out << par.m_path << " " << node << endl;
219  // check children
220  PrintPar cpar[2];
221  ndbrequire(strlen(par.m_path) + 1 < sizeof(par.m_path));
222  for (unsigned i = 0; i <= 1; i++) {
223  sprintf(cpar[i].m_path, "%s%c", par.m_path, "LR"[i]);
224  cpar[i].m_side = i;
225  cpar[i].m_depth = 0;
226  cpar[i].m_parent = loc;
227  printNode(ctx, frag, out, node.getLink(i), cpar[i]);
228  if (! cpar[i].m_ok) {
229  par.m_ok = false;
230  }
231  }
232  static const char* const sep = " *** ";
233  // check child-parent links
234  if (node.getLink(2) != par.m_parent) {
235  par.m_ok = false;
236  out << par.m_path << sep;
237  out << "parent loc " << hex << node.getLink(2);
238  out << " should be " << hex << par.m_parent << endl;
239  }
240  if (node.getSide() != par.m_side) {
241  par.m_ok = false;
242  out << par.m_path << sep;
243  out << "side " << dec << node.getSide();
244  out << " should be " << dec << par.m_side << endl;
245  }
246  // check balance
247  const int balance = -cpar[0].m_depth + cpar[1].m_depth;
248  if (node.getBalance() != balance) {
249  par.m_ok = false;
250  out << par.m_path << sep;
251  out << "balance " << node.getBalance();
252  out << " should be " << balance << endl;
253  }
254  if (abs(node.getBalance()) > 1) {
255  par.m_ok = false;
256  out << par.m_path << sep;
257  out << "balance " << node.getBalance() << " is invalid" << endl;
258  }
259  // check occupancy
260  if (node.getOccup() == 0 || node.getOccup() > tree.m_maxOccup) {
261  par.m_ok = false;
262  out << par.m_path << sep;
263  out << "occupancy " << node.getOccup();
264  out << " zero or greater than max " << tree.m_maxOccup << endl;
265  }
266  // check for occupancy of interior node
267  if (node.getChilds() == 2 && node.getOccup() < tree.m_minOccup) {
268  par.m_ok = false;
269  out << par.m_path << sep;
270  out << "occupancy " << node.getOccup() << " of interior node";
271  out << " less than min " << tree.m_minOccup << endl;
272  }
273 #ifdef dbtux_totally_groks_t_trees
274  // check missed semi-leaf/leaf merge
275  for (unsigned i = 0; i <= 1; i++) {
276  if (node.getLink(i) != NullTupLoc &&
277  node.getLink(1 - i) == NullTupLoc &&
278  // our semi-leaf seems to satify interior minOccup condition
279  node.getOccup() < tree.m_minOccup) {
280  par.m_ok = false;
281  out << par.m_path << sep;
282  out << "missed merge with child " << i << endl;
283  }
284  }
285 #endif
286  // check inline prefix
287  {
288  KeyDataC keyData1(index.m_keySpec, false);
289  const Uint32* data1 = node.getPref();
290  keyData1.set_buf(data1, index.m_prefBytes, index.m_prefAttrs);
291  KeyData keyData2(index.m_keySpec, false, 0);
292  Uint32 data2[MaxPrefSize];
293  keyData2.set_buf(data2, MaxPrefSize << 2);
294  readKeyAttrs(ctx, frag, node.getEnt(0), keyData2, index.m_prefAttrs);
295  if (cmpSearchKey(ctx, keyData1, keyData2, index.m_prefAttrs) != 0) {
296  par.m_ok = false;
297  out << par.m_path << sep;
298  out << "inline prefix mismatch" << endl;
299  }
300  }
301  // check ordering within node
302  for (unsigned j = 1; j < node.getOccup(); j++) {
303  const TreeEnt ent1 = node.getEnt(j - 1);
304  const TreeEnt ent2 = node.getEnt(j);
305  KeyData entryKey1(index.m_keySpec, false, 0);
306  KeyData entryKey2(index.m_keySpec, false, 0);
307  entryKey1.set_buf(ctx.c_searchKey, MaxAttrDataSize << 2);
308  entryKey2.set_buf(ctx.c_entryKey, MaxAttrDataSize << 2);
309  readKeyAttrs(ctx, frag, ent1, entryKey1, index.m_numAttrs);
310  readKeyAttrs(ctx, frag, ent2, entryKey2, index.m_numAttrs);
311  int ret = cmpSearchKey(ctx, entryKey1, entryKey2, index.m_numAttrs);
312  if (ret == 0)
313  ret = ent1.cmp(ent2);
314  if (! (ret < 0)) {
315  par.m_ok = false;
316  out << par.m_path << sep;
317  out << " disorder within node at pos " << j << endl;
318  }
319  }
320  // check ordering wrt subtrees
321  for (unsigned i = 0; i <= 1; i++) {
322  if (node.getLink(i) == NullTupLoc)
323  continue;
324  const TreeEnt ent1 = cpar[i].m_minmax[1 - i];
325  const unsigned pos = (i == 0 ? 0 : node.getOccup() - 1);
326  const TreeEnt ent2 = node.getEnt(pos);
327  KeyData entryKey1(index.m_keySpec, false, 0);
328  KeyData entryKey2(index.m_keySpec, false, 0);
329  entryKey1.set_buf(ctx.c_searchKey, MaxAttrDataSize << 2);
330  entryKey2.set_buf(ctx.c_entryKey, MaxAttrDataSize << 2);
331  readKeyAttrs(ctx, frag, ent1, entryKey1, index.m_numAttrs);
332  readKeyAttrs(ctx, frag, ent2, entryKey2, index.m_numAttrs);
333  int ret = cmpSearchKey(ctx, entryKey1, entryKey2, index.m_numAttrs);
334  if (ret == 0)
335  ret = ent1.cmp(ent2);
336  if ((i == 0 && ! (ret < 0)) ||
337  (i == 1 && ! (ret > 0))) {
338  par.m_ok = false;
339  out << par.m_path << sep;
340  out << " disorder wrt subtree " << i << endl;
341  }
342  }
343  // return values
344  par.m_depth = 1 + max(cpar[0].m_depth, cpar[1].m_depth);
345  par.m_occup = node.getOccup();
346  for (unsigned i = 0; i <= 1; i++) {
347  if (node.getLink(i) == NullTupLoc) {
348  const unsigned pos = (i == 0 ? 0 : node.getOccup() - 1);
349  par.m_minmax[i] = node.getEnt(pos);
350  } else
351  par.m_minmax[i] = cpar[i].m_minmax[i];
352  }
353 }
354 
355 NdbOut&
356 operator<<(NdbOut& out, const Dbtux::TupLoc& loc)
357 {
358  if (loc == Dbtux::NullTupLoc) {
359  out << "null";
360  } else {
361  out << dec << loc.getPageId();
362  out << "." << dec << loc.getPageOffset();
363  }
364  return out;
365 }
366 
367 NdbOut&
368 operator<<(NdbOut& out, const Dbtux::TreeEnt& ent)
369 {
370  out << ent.m_tupLoc;
371  out << "-" << dec << ent.m_tupVersion;
372  return out;
373 }
374 
375 NdbOut&
376 operator<<(NdbOut& out, const Dbtux::TreeNode& node)
377 {
378  out << "[TreeNode " << hex << &node;
379  out << " [left " << node.m_link[0] << "]";
380  out << " [right " << node.m_link[1] << "]";
381  out << " [up " << node.m_link[2] << "]";
382  out << " [side " << dec << node.m_side << "]";
383  out << " [occup " << dec << node.m_occup << "]";
384  out << " [balance " << dec << (int)node.m_balance - 1 << "]";
385  out << " [nodeScan " << hex << node.m_nodeScan << "]";
386  out << "]";
387  return out;
388 }
389 
390 NdbOut&
391 operator<<(NdbOut& out, const Dbtux::TreeHead& tree)
392 {
393  out << "[TreeHead " << hex << &tree;
394  out << " [nodeSize " << dec << tree.m_nodeSize << "]";
395  out << " [prefSize " << dec << tree.m_prefSize << "]";
396  out << " [minOccup " << dec << tree.m_minOccup << "]";
397  out << " [maxOccup " << dec << tree.m_maxOccup << "]";
398  out << " [root " << hex << tree.m_root << "]";
399  out << "]";
400  return out;
401 }
402 
403 NdbOut&
404 operator<<(NdbOut& out, const Dbtux::TreePos& pos)
405 {
406  out << "[TreePos " << hex << &pos;
407  out << " [loc " << pos.m_loc << "]";
408  out << " [pos " << dec << pos.m_pos << "]";
409  out << " [dir " << dec << pos.m_dir << "]";
410  out << "]";
411  return out;
412 }
413 
414 NdbOut&
415 operator<<(NdbOut& out, const Dbtux::ScanOp& scan)
416 {
417  Dbtux* tux = (Dbtux*)globalData.getBlock(DBTUX);
418  out << "[ScanOp " << hex << &scan;
419  out << " [state " << dec << scan.m_state << "]";
420  out << " [lockwait " << dec << scan.m_lockwait << "]";
421  out << " [errorCode " << dec << scan.m_errorCode << "]";
422  out << " [indexId " << dec << scan.m_indexId << "]";
423  out << " [fragId " << dec << scan.m_fragId << "]";
424  out << " [transId " << hex << scan.m_transId1 << " " << scan.m_transId2 << "]";
425  out << " [savePointId " << dec << scan.m_savePointId << "]";
426  out << " [accLockOp " << hex << scan.m_accLockOp << "]";
427  out << " [accLockOps";
428  if (globalData.isNdbMtLqh)//TODO
429  return out;
430  {
431  DLFifoList<Dbtux::ScanLock>::Head head = scan.m_accLockOps;
432  LocalDLFifoList<Dbtux::ScanLock> list(tux->c_scanLockPool, head);
433  Dbtux::ScanLockPtr lockPtr;
434  list.first(lockPtr);
435  while (lockPtr.i != RNIL) {
436  out << " " << hex << lockPtr.p->m_accLockOp;
437  list.next(lockPtr);
438  }
439  }
440  out << "]";
441  out << " [readCommitted " << dec << scan.m_readCommitted << "]";
442  out << " [lockMode " << dec << scan.m_lockMode << "]";
443  out << " [descending " << dec << scan.m_descending << "]";
444  out << " [pos " << scan.m_scanPos << "]";
445  out << " [ent " << scan.m_scanEnt << "]";
446  for (unsigned i = 0; i <= 1; i++) {
447  const Dbtux::ScanBound scanBound = scan.m_scanBound[i];
448  const Dbtux::Index& index = *tux->c_indexPool.getPtr(scan.m_indexId);
449  Dbtux::KeyDataC keyBoundData(index.m_keySpec, true);
450  Dbtux::KeyBoundC keyBound(keyBoundData);
451  tux->unpackBound(tux->c_ctx, scanBound, keyBound);
452  out << " [scanBound " << dec << i;
453  out << " " << keyBound.print(tux->c_ctx.c_debugBuffer, Dbtux::DebugBufferBytes);
454  out << "]";
455  }
456  return out;
457 }
458 
459 NdbOut&
460 operator<<(NdbOut& out, const Dbtux::Index& index)
461 {
462  Dbtux* tux = (Dbtux*)globalData.getBlock(DBTUX);
463  out << "[Index " << hex << &index;
464  out << " [tableId " << dec << index.m_tableId << "]";
465  out << " [numFrags " << dec << index.m_numFrags << "]";
466  if (globalData.isNdbMtLqh)//TODO
467  return out;
468  for (unsigned i = 0; i < index.m_numFrags; i++) {
469  out << " [frag " << dec << i << " ";
470  const Dbtux::Frag& frag = *tux->c_fragPool.getPtr(index.m_fragPtrI[i]);
471  out << frag;
472  out << "]";
473  }
474  out << " [descPage " << hex << index.m_descPage << "]";
475  out << " [descOff " << dec << index.m_descOff << "]";
476  out << " [numAttrs " << dec << index.m_numAttrs << "]";
477  out << " [prefAttrs " << dec << index.m_prefAttrs << "]";
478  out << " [prefBytes " << dec << index.m_prefBytes << "]";
479  out << " [statFragPtrI " << hex << index.m_statFragPtrI << "]";
480  out << " [statLoadTime " << dec << index.m_statLoadTime << "]";
481  out << "]";
482  return out;
483 }
484 
485 NdbOut&
486 operator<<(NdbOut& out, const Dbtux::Frag& frag)
487 {
488  out << "[Frag " << hex << &frag;
489  out << " [tableId " << dec << frag.m_tableId << "]";
490  out << " [indexId " << dec << frag.m_indexId << "]";
491  out << " [fragId " << dec << frag.m_fragId << "]";
492  out << " [entryCount " << dec << frag.m_entryCount << "]";
493  out << " [entryBytes " << dec << frag.m_entryBytes << "]";
494  out << " [entryOps " << dec << frag.m_entryOps << "]";
495  out << " [tree " << frag.m_tree << "]";
496  out << "]";
497  return out;
498 }
499 
500 NdbOut&
501 operator<<(NdbOut& out, const Dbtux::FragOp& fragOp)
502 {
503  out << "[FragOp " << hex << &fragOp;
504  out << " [userPtr " << dec << fragOp.m_userPtr << "]";
505  out << " [indexId " << dec << fragOp.m_indexId << "]";
506  out << " [fragId " << dec << fragOp.m_fragId << "]";
507  out << " [fragNo " << dec << fragOp.m_fragNo << "]";
508  out << " numAttrsRecvd " << dec << fragOp.m_numAttrsRecvd << "]";
509  out << "]";
510  return out;
511 }
512 
513 NdbOut&
514 operator<<(NdbOut& out, const Dbtux::NodeHandle& node)
515 {
516  const Dbtux::Frag& frag = node.m_frag;
517  const Dbtux::TreeHead& tree = frag.m_tree;
518  out << "[NodeHandle " << hex << &node;
519  out << " [loc " << node.m_loc << "]";
520  out << " [node " << *node.m_node << "]";
521  const Uint32* data;
522  out << " [pref";
523  data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize;
524  for (unsigned j = 0; j < tree.m_prefSize; j++)
525  out << " " << hex << data[j];
526  out << "]";
527  out << " [entList";
528  unsigned numpos = node.m_node->m_occup;
529  data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize;
530  const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data;
531  for (unsigned pos = 0; pos < numpos; pos++)
532  out << " " << entList[pos];
533  out << "]";
534  out << "]";
535  return out;
536 }
537 
538 NdbOut&
539 operator<<(NdbOut& out, const Dbtux::StatOp& stat)
540 {
541  out << "[StatOp " << hex << &stat;
542  out << " [saveSize " << dec << stat.m_saveSize << "]";
543  out << " [saveScale " << dec << stat.m_saveScale << "]";
544  out << " [batchSize " << dec << stat.m_batchSize << "]";
545  out << "]";
546  return out;
547 }
548 
549 NdbOut&
550 operator<<(NdbOut& out, const Dbtux::StatMon& mon)
551 {
552  out << "[StatMon";
553  out << " [loopIndexId " << dec << mon.m_loopIndexId << "]";
554  out << "]";
555  return out;
556 }
557 
558 #endif