MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtuxNode.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_NODE_CPP
19 #include "Dbtux.hpp"
20 
21 /*
22  * Allocate index node in TUP.
23  */
24 int
25 Dbtux::allocNode(TuxCtx& ctx, NodeHandle& node)
26 {
27  if (ERROR_INSERTED(12007)) {
28  jam();
29  CLEAR_ERROR_INSERT_VALUE;
30  return TuxMaintReq::NoMemError;
31  }
32  Frag& frag = node.m_frag;
33  Uint32 pageId = NullTupLoc.getPageId();
34  Uint32 pageOffset = NullTupLoc.getPageOffset();
35  Uint32* node32 = 0;
36  int errorCode = c_tup->tuxAllocNode(ctx.jamBuffer,
37  frag.m_tupIndexFragPtrI,
38  pageId, pageOffset, node32);
39  thrjamEntry(ctx.jamBuffer);
40  if (errorCode == 0) {
41  thrjam(ctx.jamBuffer);
42  node.m_loc = TupLoc(pageId, pageOffset);
43  node.m_node = reinterpret_cast<TreeNode*>(node32);
44  ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0);
45  } else {
46  switch (errorCode) {
47  case 827:
48  errorCode = TuxMaintReq::NoMemError;
49  break;
50  }
51  }
52  return errorCode;
53 }
54 
55 /*
56  * Free index node in TUP
57  */
58 void
59 Dbtux::freeNode(NodeHandle& node)
60 {
61  Frag& frag = node.m_frag;
62  Uint32 pageId = node.m_loc.getPageId();
63  Uint32 pageOffset = node.m_loc.getPageOffset();
64  Uint32* node32 = reinterpret_cast<Uint32*>(node.m_node);
65  c_tup->tuxFreeNode(frag.m_tupIndexFragPtrI,
66  pageId, pageOffset, node32);
67  jamEntry();
68  // invalidate the handle
69  node.m_loc = NullTupLoc;
70  node.m_node = 0;
71 }
72 
73 /*
74  * Set handle to point to existing node.
75  */
76 void
77 Dbtux::selectNode(NodeHandle& node, TupLoc loc)
78 {
79  Frag& frag = node.m_frag;
80  ndbrequire(loc != NullTupLoc);
81  Uint32 pageId = loc.getPageId();
82  Uint32 pageOffset = loc.getPageOffset();
83  Uint32* node32 = 0;
84  c_tup->tuxGetNode(frag.m_tupIndexFragPtrI, pageId, pageOffset, node32);
85  node.m_loc = loc;
86  node.m_node = reinterpret_cast<TreeNode*>(node32);
87  ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0);
88 }
89 
90 /*
91  * Set handle to point to new node. Uses a pre-allocated node.
92  */
93 void
94 Dbtux::insertNode(NodeHandle& node)
95 {
96  Frag& frag = node.m_frag;
97  // use up pre-allocated node
98  selectNode(node, frag.m_freeLoc);
99  frag.m_freeLoc = NullTupLoc;
100  new (node.m_node) TreeNode();
101 #ifdef VM_TRACE
102  TreeHead& tree = frag.m_tree;
103  memset(node.getPref(), DataFillByte, tree.m_prefSize << 2);
104  TreeEnt* entList = tree.getEntList(node.m_node);
105  memset(entList, NodeFillByte, tree.m_maxOccup * (TreeEntSize << 2));
106 #endif
107 }
108 
109 /*
110  * Delete existing node. Make it the pre-allocated free node if there
111  * is none. Otherwise return it to fragment's free list.
112  */
113 void
114 Dbtux::deleteNode(NodeHandle& node)
115 {
116  Frag& frag = node.m_frag;
117  ndbrequire(node.getOccup() == 0);
118  if (frag.m_freeLoc == NullTupLoc)
119  {
120  jam();
121  frag.m_freeLoc = node.m_loc;
122  // invalidate the handle
123  node.m_loc = NullTupLoc;
124  node.m_node = 0;
125  }
126  else
127  {
128  jam();
129  freeNode(node);
130  }
131 }
132 
133 /*
134  * Free the pre-allocated node, called when tree is empty. This avoids
135  * leaving any used pages in DataMemory.
136  */
137 void
138 Dbtux::freePreallocatedNode(Frag& frag)
139 {
140  if (frag.m_freeLoc != NullTupLoc)
141  {
142  jam();
143  NodeHandle node(frag);
144  selectNode(node, frag.m_freeLoc);
145  freeNode(node);
146  frag.m_freeLoc = NullTupLoc;
147  }
148 }
149 
150 /*
151  * Set prefix. Copies the defined number of attributes.
152  */
153 void
154 Dbtux::setNodePref(TuxCtx & ctx, NodeHandle& node)
155 {
156  const Frag& frag = node.m_frag;
157  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
158  /*
159  * bug#12873640
160  * Node prefix exists if it has non-zero number of attributes. It is
161  * then a partial instance of KeyData. If the prefix does not exist
162  * then set_buf() could overwrite m_pageId1 in first entry, causing
163  * random crash in TUP via readKeyAttrs().
164  */
165  if (index.m_prefAttrs > 0) {
166  KeyData prefKey(index.m_keySpec, false, 0);
167  prefKey.set_buf(node.getPref(), index.m_prefBytes);
168  jam();
169  readKeyAttrs(ctx, frag, node.getEnt(0), prefKey, index.m_prefAttrs);
170 #ifdef VM_TRACE
171  if (debugFlags & DebugMaint) {
172  debugOut << "setNodePref: " << node;
173  debugOut << " " << prefKey.print(ctx.c_debugBuffer, DebugBufferBytes);
174  debugOut << endl;
175  }
176 #endif
177  }
178 }
179 
180 // node operations
181 
182 /*
183  * Add entry at position. Move entries greater than or equal to the old
184  * one (if any) to the right.
185  *
186  * X
187  * v
188  * A B C D E _ _ => A B C X D E _
189  * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
190  *
191  * Add list of scans at the new entry.
192  */
193 void
194 Dbtux::nodePushUp(TuxCtx & ctx, NodeHandle& node, unsigned pos, const TreeEnt& ent, Uint32 scanList)
195 {
196  Frag& frag = node.m_frag;
197  TreeHead& tree = frag.m_tree;
198  const unsigned occup = node.getOccup();
199  ndbrequire(occup < tree.m_maxOccup && pos <= occup);
200  // fix old scans
201  if (node.getNodeScan() != RNIL)
202  nodePushUpScans(node, pos);
203  // fix node
204  TreeEnt* const entList = tree.getEntList(node.m_node);
205  for (unsigned i = occup; i > pos; i--) {
206  thrjam(ctx.jamBuffer);
207  entList[i] = entList[i - 1];
208  }
209  entList[pos] = ent;
210  node.setOccup(occup + 1);
211  // add new scans
212  if (scanList != RNIL)
213  addScanList(node, pos, scanList);
214  // fix prefix
215  if (occup == 0 || pos == 0)
216  setNodePref(ctx, node);
217 }
218 
219 void
220 Dbtux::nodePushUpScans(NodeHandle& node, unsigned pos)
221 {
222  const unsigned occup = node.getOccup();
223  ScanOpPtr scanPtr;
224  scanPtr.i = node.getNodeScan();
225  do {
226  jam();
227  c_scanOpPool.getPtr(scanPtr);
228  TreePos& scanPos = scanPtr.p->m_scanPos;
229  ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
230  if (scanPos.m_pos >= pos) {
231  jam();
232 #ifdef VM_TRACE
233  if (debugFlags & DebugScan) {
234  debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
235  debugOut << "At pushUp pos=" << pos << " " << node << endl;
236  }
237 #endif
238  scanPos.m_pos++;
239  }
240  scanPtr.i = scanPtr.p->m_nodeScan;
241  } while (scanPtr.i != RNIL);
242 }
243 
244 /*
245  * Remove and return entry at position. Move entries greater than the
246  * removed one to the left. This is the opposite of nodePushUp.
247  *
248  * D
249  * ^ ^
250  * A B C D E F _ => A B C E F _ _
251  * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
252  *
253  * Scans at removed entry are returned if non-zero location is passed or
254  * else moved forward.
255  */
256 void
257 Dbtux::nodePopDown(TuxCtx& ctx, NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32* scanList)
258 {
259  Frag& frag = node.m_frag;
260  TreeHead& tree = frag.m_tree;
261  const unsigned occup = node.getOccup();
262  ndbrequire(occup <= tree.m_maxOccup && pos < occup);
263  if (node.getNodeScan() != RNIL) {
264  // remove or move scans at this position
265  if (scanList == 0)
266  moveScanList(node, pos);
267  else
268  removeScanList(node, pos, *scanList);
269  // fix other scans
270  if (node.getNodeScan() != RNIL)
271  nodePopDownScans(node, pos);
272  }
273  // fix node
274  TreeEnt* const entList = tree.getEntList(node.m_node);
275  ent = entList[pos];
276  for (unsigned i = pos; i < occup - 1; i++) {
277  thrjam(ctx.jamBuffer);
278  entList[i] = entList[i + 1];
279  }
280  node.setOccup(occup - 1);
281  // fix prefix
282  if (occup != 1 && pos == 0)
283  setNodePref(ctx, node);
284 }
285 
286 void
287 Dbtux::nodePopDownScans(NodeHandle& node, unsigned pos)
288 {
289  const unsigned occup = node.getOccup();
290  ScanOpPtr scanPtr;
291  scanPtr.i = node.getNodeScan();
292  do {
293  jam();
294  c_scanOpPool.getPtr(scanPtr);
295  TreePos& scanPos = scanPtr.p->m_scanPos;
296  ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
297  // handled before
298  ndbrequire(scanPos.m_pos != pos);
299  if (scanPos.m_pos > pos) {
300  jam();
301 #ifdef VM_TRACE
302  if (debugFlags & DebugScan) {
303  debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
304  debugOut << "At popDown pos=" << pos << " " << node << endl;
305  }
306 #endif
307  scanPos.m_pos--;
308  }
309  scanPtr.i = scanPtr.p->m_nodeScan;
310  } while (scanPtr.i != RNIL);
311 }
312 
313 /*
314  * Add entry at existing position. Move entries less than or equal to
315  * the old one to the left. Remove and return old min entry.
316  *
317  * X A
318  * ^ v ^
319  * A B C D E _ _ => B C D X E _ _
320  * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
321  *
322  * Return list of scans at the removed position 0.
323  */
324 void
325 Dbtux::nodePushDown(TuxCtx& ctx, NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32& scanList)
326 {
327  Frag& frag = node.m_frag;
328  TreeHead& tree = frag.m_tree;
329  const unsigned occup = node.getOccup();
330  ndbrequire(occup <= tree.m_maxOccup && pos < occup);
331  if (node.getNodeScan() != RNIL) {
332  // remove scans at 0
333  removeScanList(node, 0, scanList);
334  // fix other scans
335  if (node.getNodeScan() != RNIL)
336  nodePushDownScans(node, pos);
337  }
338  // fix node
339  TreeEnt* const entList = tree.getEntList(node.m_node);
340  TreeEnt oldMin = entList[0];
341  for (unsigned i = 0; i < pos; i++) {
342  thrjam(ctx.jamBuffer);
343  entList[i] = entList[i + 1];
344  }
345  entList[pos] = ent;
346  ent = oldMin;
347  // fix prefix
348  if (true)
349  setNodePref(ctx, node);
350 }
351 
352 void
353 Dbtux::nodePushDownScans(NodeHandle& node, unsigned pos)
354 {
355  const unsigned occup = node.getOccup();
356  ScanOpPtr scanPtr;
357  scanPtr.i = node.getNodeScan();
358  do {
359  jam();
360  c_scanOpPool.getPtr(scanPtr);
361  TreePos& scanPos = scanPtr.p->m_scanPos;
362  ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
363  // handled before
364  ndbrequire(scanPos.m_pos != 0);
365  if (scanPos.m_pos <= pos) {
366  jam();
367 #ifdef VM_TRACE
368  if (debugFlags & DebugScan) {
369  debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
370  debugOut << "At pushDown pos=" << pos << " " << node << endl;
371  }
372 #endif
373  scanPos.m_pos--;
374  }
375  scanPtr.i = scanPtr.p->m_nodeScan;
376  } while (scanPtr.i != RNIL);
377 }
378 
379 /*
380  * Remove and return entry at position. Move entries less than the
381  * removed one to the right. Replace min entry by the input entry.
382  * This is the opposite of nodePushDown.
383  *
384  * X D
385  * v ^ ^
386  * A B C D E _ _ => X A B C E _ _
387  * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
388  *
389  * Move scans at removed entry and add scans at the new entry.
390  */
391 void
392 Dbtux::nodePopUp(TuxCtx& ctx, NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32 scanList)
393 {
394  Frag& frag = node.m_frag;
395  TreeHead& tree = frag.m_tree;
396  const unsigned occup = node.getOccup();
397  ndbrequire(occup <= tree.m_maxOccup && pos < occup);
398  if (node.getNodeScan() != RNIL) {
399  // move scans whose entry disappears
400  moveScanList(node, pos);
401  // fix other scans
402  if (node.getNodeScan() != RNIL)
403  nodePopUpScans(node, pos);
404  }
405  // fix node
406  TreeEnt* const entList = tree.getEntList(node.m_node);
407  TreeEnt newMin = ent;
408  ent = entList[pos];
409  for (unsigned i = pos; i > 0; i--) {
410  thrjam(ctx.jamBuffer);
411  entList[i] = entList[i - 1];
412  }
413  entList[0] = newMin;
414  // add scans
415  if (scanList != RNIL)
416  addScanList(node, 0, scanList);
417  // fix prefix
418  if (true)
419  setNodePref(ctx, node);
420 }
421 
422 void
423 Dbtux::nodePopUpScans(NodeHandle& node, unsigned pos)
424 {
425  const unsigned occup = node.getOccup();
426  ScanOpPtr scanPtr;
427  scanPtr.i = node.getNodeScan();
428  do {
429  jam();
430  c_scanOpPool.getPtr(scanPtr);
431  TreePos& scanPos = scanPtr.p->m_scanPos;
432  ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
433  ndbrequire(scanPos.m_pos != pos);
434  if (scanPos.m_pos < pos) {
435  jam();
436 #ifdef VM_TRACE
437  if (debugFlags & DebugScan) {
438  debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
439  debugOut << "At popUp pos=" << pos << " " << node << endl;
440  }
441 #endif
442  scanPos.m_pos++;
443  }
444  scanPtr.i = scanPtr.p->m_nodeScan;
445  } while (scanPtr.i != RNIL);
446 }
447 
448 /*
449  * Move number of entries from another node to this node before the min
450  * (i=0) or after the max (i=1). Expensive but not often used.
451  */
452 void
453 Dbtux::nodeSlide(TuxCtx& ctx, NodeHandle& dstNode, NodeHandle& srcNode, unsigned cnt, unsigned i)
454 {
455  ndbrequire(i <= 1);
456  while (cnt != 0) {
457  TreeEnt ent;
458  Uint32 scanList = RNIL;
459  nodePopDown(ctx, srcNode, i == 0 ? srcNode.getOccup() - 1 : 0, ent, &scanList);
460  nodePushUp(ctx, dstNode, i == 0 ? 0 : dstNode.getOccup(), ent, scanList);
461  cnt--;
462  }
463 }
464 
465 // scans linked to node
466 
467 
468 /*
469  * Add list of scans to node at given position.
470  */
471 void
472 Dbtux::addScanList(NodeHandle& node, unsigned pos, Uint32 scanList)
473 {
474  ScanOpPtr scanPtr;
475  scanPtr.i = scanList;
476  do {
477  jam();
478  c_scanOpPool.getPtr(scanPtr);
479 #ifdef VM_TRACE
480  if (debugFlags & DebugScan) {
481  debugOut << "Add scan " << scanPtr.i << " " << *scanPtr.p << endl;
482  debugOut << "To pos=" << pos << " " << node << endl;
483  }
484 #endif
485  const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
486  scanPtr.p->m_nodeScan = RNIL;
487  linkScan(node, scanPtr);
488  TreePos& scanPos = scanPtr.p->m_scanPos;
489  // set position but leave direction alone
490  scanPos.m_loc = node.m_loc;
491  scanPos.m_pos = pos;
492  scanPtr.i = nextPtrI;
493  } while (scanPtr.i != RNIL);
494 }
495 
496 /*
497  * Remove list of scans from node at given position. The return
498  * location must point to existing list (in fact RNIL always).
499  */
500 void
501 Dbtux::removeScanList(NodeHandle& node, unsigned pos, Uint32& scanList)
502 {
503  ScanOpPtr scanPtr;
504  scanPtr.i = node.getNodeScan();
505  do {
506  jam();
507  c_scanOpPool.getPtr(scanPtr);
508  const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
509  TreePos& scanPos = scanPtr.p->m_scanPos;
510  ndbrequire(scanPos.m_loc == node.m_loc);
511  if (scanPos.m_pos == pos) {
512  jam();
513 #ifdef VM_TRACE
514  if (debugFlags & DebugScan) {
515  debugOut << "Remove scan " << scanPtr.i << " " << *scanPtr.p << endl;
516  debugOut << "Fron pos=" << pos << " " << node << endl;
517  }
518 #endif
519  unlinkScan(node, scanPtr);
520  scanPtr.p->m_nodeScan = scanList;
521  scanList = scanPtr.i;
522  // unset position but leave direction alone
523  scanPos.m_loc = NullTupLoc;
524  scanPos.m_pos = ZNIL;
525  }
526  scanPtr.i = nextPtrI;
527  } while (scanPtr.i != RNIL);
528 }
529 
530 /*
531  * Move list of scans away from entry about to be removed. Uses scan
532  * method scanNext().
533  */
534 void
535 Dbtux::moveScanList(NodeHandle& node, unsigned pos)
536 {
537  ScanOpPtr scanPtr;
538  scanPtr.i = node.getNodeScan();
539  do {
540  jam();
541  c_scanOpPool.getPtr(scanPtr);
542  TreePos& scanPos = scanPtr.p->m_scanPos;
543  const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
544  ndbrequire(scanPos.m_loc == node.m_loc);
545  if (scanPos.m_pos == pos) {
546  jam();
547 #ifdef VM_TRACE
548  if (debugFlags & DebugScan) {
549  debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl;
550  debugOut << "At pos=" << pos << " " << node << endl;
551  }
552 #endif
553  scanNext(scanPtr, true);
554  ndbrequire(! (scanPos.m_loc == node.m_loc && scanPos.m_pos == pos));
555  }
556  scanPtr.i = nextPtrI;
557  } while (scanPtr.i != RNIL);
558 }
559 
560 /*
561  * Link scan to the list under the node. The list is single-linked and
562  * ordering does not matter.
563  */
564 void
565 Dbtux::linkScan(NodeHandle& node, ScanOpPtr scanPtr)
566 {
567 #ifdef VM_TRACE
568  if (debugFlags & DebugScan) {
569  debugOut << "Link scan " << scanPtr.i << " " << *scanPtr.p << endl;
570  debugOut << "To node " << node << endl;
571  }
572 #endif
573  ndbrequire(! islinkScan(node, scanPtr) && scanPtr.p->m_nodeScan == RNIL);
574  scanPtr.p->m_nodeScan = node.getNodeScan();
575  node.setNodeScan(scanPtr.i);
576 }
577 
578 /*
579  * Unlink a scan from the list under the node.
580  */
581 void
582 Dbtux::unlinkScan(NodeHandle& node, ScanOpPtr scanPtr)
583 {
584 #ifdef VM_TRACE
585  if (debugFlags & DebugScan) {
586  debugOut << "Unlink scan " << scanPtr.i << " " << *scanPtr.p << endl;
587  debugOut << "From node " << node << endl;
588  }
589 #endif
590  ScanOpPtr currPtr;
591  currPtr.i = node.getNodeScan();
592  ScanOpPtr prevPtr;
593  prevPtr.i = RNIL;
594  while (true) {
595  jam();
596  c_scanOpPool.getPtr(currPtr);
597  Uint32 nextPtrI = currPtr.p->m_nodeScan;
598  if (currPtr.i == scanPtr.i) {
599  jam();
600  if (prevPtr.i == RNIL) {
601  node.setNodeScan(nextPtrI);
602  } else {
603  jam();
604  prevPtr.p->m_nodeScan = nextPtrI;
605  }
606  scanPtr.p->m_nodeScan = RNIL;
607  // check for duplicates
608  ndbrequire(! islinkScan(node, scanPtr));
609  return;
610  }
611  prevPtr = currPtr;
612  currPtr.i = nextPtrI;
613  }
614 }
615 
616 /*
617  * Check if a scan is linked to this node. Only for ndbrequire.
618  */
619 bool
620 Dbtux::islinkScan(NodeHandle& node, ScanOpPtr scanPtr)
621 {
622  ScanOpPtr currPtr;
623  currPtr.i = node.getNodeScan();
624  while (currPtr.i != RNIL) {
625  jam();
626  c_scanOpPool.getPtr(currPtr);
627  if (currPtr.i == scanPtr.i) {
628  jam();
629  return true;
630  }
631  currPtr.i = currPtr.p->m_nodeScan;
632  }
633  return false;
634 }
635 
636 void
637 Dbtux::NodeHandle::progError(int line, int cause, const char* file)
638 {
639  ErrorReporter::handleAssert("Dbtux::NodeHandle: assert failed", file, line);
640 }