1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#define DBTUX_NODE_CPP
20
* Allocate index node in TUP.
23
Dbtux::allocNode(Signal* signal, NodeHandle& node)
25
if (ERROR_INSERTED(12007)) {
27
CLEAR_ERROR_INSERT_VALUE;
28
return TuxMaintReq::NoMemError;
30
Frag& frag = node.m_frag;
31
Uint32 pageId = NullTupLoc.getPageId();
32
Uint32 pageOffset = NullTupLoc.getPageOffset();
34
int errorCode = c_tup->tuxAllocNode(signal, frag.m_tupIndexFragPtrI, pageId, pageOffset, node32);
38
node.m_loc = TupLoc(pageId, pageOffset);
39
node.m_node = reinterpret_cast<TreeNode*>(node32);
40
ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0);
44
errorCode = TuxMaintReq::NoMemError;
52
* Set handle to point to existing node.
55
Dbtux::selectNode(NodeHandle& node, TupLoc loc)
57
Frag& frag = node.m_frag;
58
ndbrequire(loc != NullTupLoc);
59
Uint32 pageId = loc.getPageId();
60
Uint32 pageOffset = loc.getPageOffset();
62
c_tup->tuxGetNode(frag.m_tupIndexFragPtrI, pageId, pageOffset, node32);
65
node.m_node = reinterpret_cast<TreeNode*>(node32);
66
ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0);
70
* Set handle to point to new node. Uses a pre-allocated node.
73
Dbtux::insertNode(NodeHandle& node)
75
Frag& frag = node.m_frag;
76
// unlink from freelist
77
selectNode(node, frag.m_freeLoc);
78
frag.m_freeLoc = node.getLink(0);
79
new (node.m_node) TreeNode();
81
TreeHead& tree = frag.m_tree;
82
memset(node.getPref(), DataFillByte, tree.m_prefSize << 2);
83
TreeEnt* entList = tree.getEntList(node.m_node);
84
memset(entList, NodeFillByte, (tree.m_maxOccup + 1) * (TreeEntSize << 2));
89
* Delete existing node. Simply put it on the freelist.
92
Dbtux::deleteNode(NodeHandle& node)
94
Frag& frag = node.m_frag;
95
ndbrequire(node.getOccup() == 0);
97
node.setLink(0, frag.m_freeLoc);
98
frag.m_freeLoc = node.m_loc;
99
// invalidate the handle
100
node.m_loc = NullTupLoc;
105
* Set prefix. Copies the number of words that fits. Includes
106
* attribute headers for now. XXX use null mask instead
109
Dbtux::setNodePref(NodeHandle& node)
111
const Frag& frag = node.m_frag;
112
const TreeHead& tree = frag.m_tree;
113
readKeyAttrs(frag, node.getMinMax(0), 0, c_entryKey);
114
copyAttrs(frag, c_entryKey, node.getPref(), tree.m_prefSize);
120
* Add entry at position. Move entries greater than or equal to the old
121
* one (if any) to the right.
125
* A B C D E _ _ => A B C X D E _
126
* 0 1 2 3 4 5 6 0 1 2 3 4 5 6
128
* Add list of scans at the new entry.
131
Dbtux::nodePushUp(NodeHandle& node, unsigned pos, const TreeEnt& ent, Uint32 scanList)
133
Frag& frag = node.m_frag;
134
TreeHead& tree = frag.m_tree;
135
const unsigned occup = node.getOccup();
136
ndbrequire(occup < tree.m_maxOccup && pos <= occup);
138
if (node.getNodeScan() != RNIL)
139
nodePushUpScans(node, pos);
141
TreeEnt* const entList = tree.getEntList(node.m_node);
142
entList[occup] = entList[0];
143
TreeEnt* const tmpList = entList + 1;
144
for (unsigned i = occup; i > pos; i--) {
146
tmpList[i] = tmpList[i - 1];
149
entList[0] = entList[occup + 1];
150
node.setOccup(occup + 1);
152
if (scanList != RNIL)
153
addScanList(node, pos, scanList);
155
if (occup == 0 || pos == 0)
160
Dbtux::nodePushUpScans(NodeHandle& node, unsigned pos)
162
const unsigned occup = node.getOccup();
164
scanPtr.i = node.getNodeScan();
167
c_scanOpPool.getPtr(scanPtr);
168
TreePos& scanPos = scanPtr.p->m_scanPos;
169
ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
170
if (scanPos.m_pos >= pos) {
173
if (debugFlags & DebugScan) {
174
debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
175
debugOut << "At pushUp pos=" << pos << " " << node << endl;
180
scanPtr.i = scanPtr.p->m_nodeScan;
181
} while (scanPtr.i != RNIL);
185
* Remove and return entry at position. Move entries greater than the
186
* removed one to the left. This is the opposite of nodePushUp.
190
* A B C D E F _ => A B C E F _ _
191
* 0 1 2 3 4 5 6 0 1 2 3 4 5 6
193
* Scans at removed entry are returned if non-zero location is passed or
194
* else moved forward.
197
Dbtux::nodePopDown(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32* scanList)
199
Frag& frag = node.m_frag;
200
TreeHead& tree = frag.m_tree;
201
const unsigned occup = node.getOccup();
202
ndbrequire(occup <= tree.m_maxOccup && pos < occup);
203
if (node.getNodeScan() != RNIL) {
204
// remove or move scans at this position
206
moveScanList(node, pos);
208
removeScanList(node, pos, *scanList);
210
if (node.getNodeScan() != RNIL)
211
nodePopDownScans(node, pos);
214
TreeEnt* const entList = tree.getEntList(node.m_node);
215
entList[occup] = entList[0];
216
TreeEnt* const tmpList = entList + 1;
218
for (unsigned i = pos; i < occup - 1; i++) {
220
tmpList[i] = tmpList[i + 1];
222
entList[0] = entList[occup - 1];
223
node.setOccup(occup - 1);
225
if (occup != 1 && pos == 0)
230
Dbtux::nodePopDownScans(NodeHandle& node, unsigned pos)
232
const unsigned occup = node.getOccup();
234
scanPtr.i = node.getNodeScan();
237
c_scanOpPool.getPtr(scanPtr);
238
TreePos& scanPos = scanPtr.p->m_scanPos;
239
ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
241
ndbrequire(scanPos.m_pos != pos);
242
if (scanPos.m_pos > pos) {
245
if (debugFlags & DebugScan) {
246
debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
247
debugOut << "At popDown pos=" << pos << " " << node << endl;
252
scanPtr.i = scanPtr.p->m_nodeScan;
253
} while (scanPtr.i != RNIL);
257
* Add entry at existing position. Move entries less than or equal to
258
* the old one to the left. Remove and return old min entry.
262
* A B C D E _ _ => B C D X E _ _
263
* 0 1 2 3 4 5 6 0 1 2 3 4 5 6
265
* Return list of scans at the removed position 0.
268
Dbtux::nodePushDown(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32& scanList)
270
Frag& frag = node.m_frag;
271
TreeHead& tree = frag.m_tree;
272
const unsigned occup = node.getOccup();
273
ndbrequire(occup <= tree.m_maxOccup && pos < occup);
274
if (node.getNodeScan() != RNIL) {
276
removeScanList(node, 0, scanList);
278
if (node.getNodeScan() != RNIL)
279
nodePushDownScans(node, pos);
282
TreeEnt* const entList = tree.getEntList(node.m_node);
283
entList[occup] = entList[0];
284
TreeEnt* const tmpList = entList + 1;
285
TreeEnt oldMin = tmpList[0];
286
for (unsigned i = 0; i < pos; i++) {
288
tmpList[i] = tmpList[i + 1];
292
entList[0] = entList[occup];
299
Dbtux::nodePushDownScans(NodeHandle& node, unsigned pos)
301
const unsigned occup = node.getOccup();
303
scanPtr.i = node.getNodeScan();
306
c_scanOpPool.getPtr(scanPtr);
307
TreePos& scanPos = scanPtr.p->m_scanPos;
308
ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
310
ndbrequire(scanPos.m_pos != 0);
311
if (scanPos.m_pos <= pos) {
314
if (debugFlags & DebugScan) {
315
debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
316
debugOut << "At pushDown pos=" << pos << " " << node << endl;
321
scanPtr.i = scanPtr.p->m_nodeScan;
322
} while (scanPtr.i != RNIL);
326
* Remove and return entry at position. Move entries less than the
327
* removed one to the right. Replace min entry by the input entry.
328
* This is the opposite of nodePushDown.
332
* A B C D E _ _ => X A B C E _ _
333
* 0 1 2 3 4 5 6 0 1 2 3 4 5 6
335
* Move scans at removed entry and add scans at the new entry.
338
Dbtux::nodePopUp(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32 scanList)
340
Frag& frag = node.m_frag;
341
TreeHead& tree = frag.m_tree;
342
const unsigned occup = node.getOccup();
343
ndbrequire(occup <= tree.m_maxOccup && pos < occup);
344
if (node.getNodeScan() != RNIL) {
345
// move scans whose entry disappears
346
moveScanList(node, pos);
348
if (node.getNodeScan() != RNIL)
349
nodePopUpScans(node, pos);
352
TreeEnt* const entList = tree.getEntList(node.m_node);
353
entList[occup] = entList[0];
354
TreeEnt* const tmpList = entList + 1;
355
TreeEnt newMin = ent;
357
for (unsigned i = pos; i > 0; i--) {
359
tmpList[i] = tmpList[i - 1];
362
entList[0] = entList[occup];
364
if (scanList != RNIL)
365
addScanList(node, 0, scanList);
372
Dbtux::nodePopUpScans(NodeHandle& node, unsigned pos)
374
const unsigned occup = node.getOccup();
376
scanPtr.i = node.getNodeScan();
379
c_scanOpPool.getPtr(scanPtr);
380
TreePos& scanPos = scanPtr.p->m_scanPos;
381
ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup);
382
ndbrequire(scanPos.m_pos != pos);
383
if (scanPos.m_pos < pos) {
386
if (debugFlags & DebugScan) {
387
debugOut << "Fix scan " << scanPtr.i << " " << *scanPtr.p << endl;
388
debugOut << "At popUp pos=" << pos << " " << node << endl;
393
scanPtr.i = scanPtr.p->m_nodeScan;
394
} while (scanPtr.i != RNIL);
398
* Move number of entries from another node to this node before the min
399
* (i=0) or after the max (i=1). Expensive but not often used.
402
Dbtux::nodeSlide(NodeHandle& dstNode, NodeHandle& srcNode, unsigned cnt, unsigned i)
407
Uint32 scanList = RNIL;
408
nodePopDown(srcNode, i == 0 ? srcNode.getOccup() - 1 : 0, ent, &scanList);
409
nodePushUp(dstNode, i == 0 ? 0 : dstNode.getOccup(), ent, scanList);
414
// scans linked to node
418
* Add list of scans to node at given position.
421
Dbtux::addScanList(NodeHandle& node, unsigned pos, Uint32 scanList)
424
scanPtr.i = scanList;
427
c_scanOpPool.getPtr(scanPtr);
429
if (debugFlags & DebugScan) {
430
debugOut << "Add scan " << scanPtr.i << " " << *scanPtr.p << endl;
431
debugOut << "To pos=" << pos << " " << node << endl;
434
const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
435
scanPtr.p->m_nodeScan = RNIL;
436
linkScan(node, scanPtr);
437
TreePos& scanPos = scanPtr.p->m_scanPos;
438
// set position but leave direction alone
439
scanPos.m_loc = node.m_loc;
441
scanPtr.i = nextPtrI;
442
} while (scanPtr.i != RNIL);
446
* Remove list of scans from node at given position. The return
447
* location must point to existing list (in fact RNIL always).
450
Dbtux::removeScanList(NodeHandle& node, unsigned pos, Uint32& scanList)
453
scanPtr.i = node.getNodeScan();
456
c_scanOpPool.getPtr(scanPtr);
457
const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
458
TreePos& scanPos = scanPtr.p->m_scanPos;
459
ndbrequire(scanPos.m_loc == node.m_loc);
460
if (scanPos.m_pos == pos) {
463
if (debugFlags & DebugScan) {
464
debugOut << "Remove scan " << scanPtr.i << " " << *scanPtr.p << endl;
465
debugOut << "Fron pos=" << pos << " " << node << endl;
468
unlinkScan(node, scanPtr);
469
scanPtr.p->m_nodeScan = scanList;
470
scanList = scanPtr.i;
471
// unset position but leave direction alone
472
scanPos.m_loc = NullTupLoc;
473
scanPos.m_pos = ZNIL;
475
scanPtr.i = nextPtrI;
476
} while (scanPtr.i != RNIL);
480
* Move list of scans away from entry about to be removed. Uses scan
484
Dbtux::moveScanList(NodeHandle& node, unsigned pos)
487
scanPtr.i = node.getNodeScan();
490
c_scanOpPool.getPtr(scanPtr);
491
TreePos& scanPos = scanPtr.p->m_scanPos;
492
const Uint32 nextPtrI = scanPtr.p->m_nodeScan;
493
ndbrequire(scanPos.m_loc == node.m_loc);
494
if (scanPos.m_pos == pos) {
497
if (debugFlags & DebugScan) {
498
debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl;
499
debugOut << "At pos=" << pos << " " << node << endl;
502
scanNext(scanPtr, true);
503
ndbrequire(! (scanPos.m_loc == node.m_loc && scanPos.m_pos == pos));
505
scanPtr.i = nextPtrI;
506
} while (scanPtr.i != RNIL);
510
* Link scan to the list under the node. The list is single-linked and
511
* ordering does not matter.
514
Dbtux::linkScan(NodeHandle& node, ScanOpPtr scanPtr)
517
if (debugFlags & DebugScan) {
518
debugOut << "Link scan " << scanPtr.i << " " << *scanPtr.p << endl;
519
debugOut << "To node " << node << endl;
522
ndbrequire(! islinkScan(node, scanPtr) && scanPtr.p->m_nodeScan == RNIL);
523
scanPtr.p->m_nodeScan = node.getNodeScan();
524
node.setNodeScan(scanPtr.i);
528
* Unlink a scan from the list under the node.
531
Dbtux::unlinkScan(NodeHandle& node, ScanOpPtr scanPtr)
534
if (debugFlags & DebugScan) {
535
debugOut << "Unlink scan " << scanPtr.i << " " << *scanPtr.p << endl;
536
debugOut << "From node " << node << endl;
540
currPtr.i = node.getNodeScan();
545
c_scanOpPool.getPtr(currPtr);
546
Uint32 nextPtrI = currPtr.p->m_nodeScan;
547
if (currPtr.i == scanPtr.i) {
549
if (prevPtr.i == RNIL) {
550
node.setNodeScan(nextPtrI);
553
prevPtr.p->m_nodeScan = nextPtrI;
555
scanPtr.p->m_nodeScan = RNIL;
556
// check for duplicates
557
ndbrequire(! islinkScan(node, scanPtr));
561
currPtr.i = nextPtrI;
566
* Check if a scan is linked to this node. Only for ndbrequire.
569
Dbtux::islinkScan(NodeHandle& node, ScanOpPtr scanPtr)
572
currPtr.i = node.getNodeScan();
573
while (currPtr.i != RNIL) {
575
c_scanOpPool.getPtr(currPtr);
576
if (currPtr.i == scanPtr.i) {
580
currPtr.i = currPtr.p->m_nodeScan;
586
Dbtux::NodeHandle::progError(int line, int cause, const char* file)
588
ErrorReporter::handleAssert("Dbtux::NodeHandle: assert failed", file, line);