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