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