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