2
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4
* @APPLE_LICENSE_HEADER_START@
6
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7
* Reserved. This file contains Original Code and/or Modifications of
8
* Original Code as defined in and that are subject to the Apple Public
9
* Source License Version 1.0 (the 'License'). You may not use this file
10
* except in compliance with the License. Please obtain a copy of the
11
* License at http://www.apple.com/publicsource and read it before using
14
* The Original Code and all software distributed under the License are
15
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19
* License for the specific language governing rights and limitations
22
* @APPLE_LICENSE_HEADER_END@
27
Contains: Multi-node tree operations for the BTree Module.
29
Version: xxx put the technology version here xxx
31
Written by: Gordon Sheridan and Bill Bruffey
33
Copyright: � 1992-1997, 1999 by Apple Computer, Inc., all rights reserved.
36
#include "BTreePrivate.h"
38
#define DEBUG_TREEOPS 0
40
/////////////////////// Routines Internal To BTree Module ///////////////////////
45
////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
47
static OSStatus AddNewRootNode (BTreeControlBlockPtr btreePtr,
49
NodeDescPtr rightNode );
51
static OSStatus CollapseTree (BTreeControlBlockPtr btreePtr,
52
BlockDescriptor *blockPtr );
54
static OSStatus RotateLeft (BTreeControlBlockPtr btreePtr,
56
NodeDescPtr rightNode,
57
UInt16 rightInsertIndex,
62
UInt32 *insertNodeNum,
64
UInt16 *recsRotated );
66
static Boolean RotateRecordLeft (BTreeControlBlockPtr btreePtr,
68
NodeDescPtr rightNode );
71
static OSStatus SplitLeft (BTreeControlBlockPtr btreePtr,
72
BlockDescriptor *leftNode,
73
BlockDescriptor *rightNode,
80
UInt32 *insertNodeNum,
81
UInt16 *recsRotated );
85
static OSStatus InsertLevel (BTreeControlBlockPtr btreePtr,
86
TreePathTable treePathTable,
87
InsertKey *primaryKey,
88
InsertKey *secondaryKey,
89
BlockDescriptor *targetNode,
94
static OSErr InsertNode (BTreeControlBlockPtr btreePtr,
96
BlockDescriptor *targetNode,
101
BlockDescriptor *leftNode,
102
Boolean *updateParent,
103
Boolean *insertParent,
104
Boolean *rootSplit );
106
static UInt16 GetKeyLength (const BTreeControlBlock *btreePtr,
108
Boolean forLeafNode );
110
static Boolean RotateRecordRight( BTreeControlBlockPtr btreePtr,
111
NodeDescPtr leftNode,
112
NodeDescPtr rightNode );
114
static OSStatus RotateRight( BTreeControlBlockPtr btreePtr,
115
NodeDescPtr leftNode,
116
NodeDescPtr rightNode,
117
UInt16 leftInsertIndex,
122
UInt32 *insertNodeNum,
124
UInt16 *recsRotated );
126
static OSStatus SplitRight( BTreeControlBlockPtr btreePtr,
127
BlockDescriptor *nodePtr,
128
BlockDescriptor *rightNodePtr,
134
UInt16 *insertIndexPtr,
135
UInt32 *newNodeNumPtr,
136
UInt16 *recsRotatedPtr );
139
static int DoKeyCheck( NodeDescPtr nodeP, BTreeControlBlock *btcb );
140
static int DoKeyCheckAcrossNodes( NodeDescPtr theLeftNodePtr,
141
NodeDescPtr theRightNodePtr,
142
BTreeControlBlock *theTreePtr,
144
static void PrintNodeDescriptor( NodeDescPtr thePtr );
145
static void PrintKey( UInt8 * myPtr, int mySize );
146
#endif // DEBUG_TREEOPS
149
/* used by InsertLevel (and called routines) to communicate the state of an insert operation */
152
kInsertParent = 0x0001,
153
kUpdateParent = 0x0002,
155
kInsertedInRight = 0x0008,
160
//////////////////////// BTree Multi-node Tree Operations ///////////////////////
163
/*-------------------------------------------------------------------------------
165
Routine: SearchTree - Search BTree for key and set up Tree Path Table.
167
Function: Searches BTree for specified key, setting up the Tree Path Table to
168
reflect the search path.
171
Input: btreePtr - pointer to control block of BTree to search
172
keyPtr - pointer to the key to search for
173
treePathTable - pointer to the tree path table to construct
175
Output: nodeNum - number of the node containing the key position
176
iterator - BTreeIterator specifying record or insert position
178
Result: noErr - key found, index is record index
179
fsBTRecordNotFoundErr - key not found, index is insert index
180
fsBTEmptyErr - key not found, return params are nil
181
otherwise - catastrophic failure (GetNode/ReleaseNode failed)
182
-------------------------------------------------------------------------------*/
184
OSStatus SearchTree (BTreeControlBlockPtr btreePtr,
185
BTreeKeyPtr searchKey,
186
TreePathTable treePathTable,
188
BlockDescriptor *nodePtr,
189
UInt16 *returnIndex )
197
SInt8 nodeKind; // Kind of current node (index/leaf)
203
curNodeNum = btreePtr->rootNode;
204
level = btreePtr->treeDepth;
206
if (level == 0) // is the tree empty?
212
//�� for debugging...
213
treePathTable [0].node = 0;
214
treePathTable [0].index = 0;
219
// [2550929] Node number 0 is the header node. It is never a valid
220
// index or leaf node. If we're ever asked to search through node 0,
221
// something has gone wrong (typically a bad child node number, or
222
// we found a node full of zeroes that we thought was an index node).
226
Panic("SearchTree: curNodeNum is zero!");
227
err = fsBTInvalidNodeErr;
231
err = GetNode (btreePtr, curNodeNum, &nodeRec);
238
// [2550929] Sanity check the node height and node type. We expect
239
// particular values at each iteration in the search. This checking
240
// quickly finds bad pointers, loops, and other damage to the
241
// hierarchy of the B-tree.
243
if (((BTNodeDescriptor*)nodeRec.buffer)->height != level)
245
err = fsBTInvalidNodeErr;
248
nodeKind = ((BTNodeDescriptor*)nodeRec.buffer)->kind;
251
// Nodes at level 1 must be leaves, by definition
252
if (nodeKind != kBTLeafNode)
254
err = fsBTInvalidNodeErr;
260
// A node at any other depth must be an index node
261
if (nodeKind != kBTIndexNode)
263
err = fsBTInvalidNodeErr;
268
keyFound = SearchNode (btreePtr, nodeRec.buffer, searchKey, &index);
270
treePathTable [level].node = curNodeNum;
272
if (nodeKind == kBTLeafNode)
274
treePathTable [level].index = index;
275
break; // were done...
278
if ( (keyFound != true) && (index != 0))
281
treePathTable [level].index = index;
283
err = GetRecordByIndex (btreePtr, nodeRec.buffer, index, &keyPtr, &dataPtr, &dataSize);
286
// [2550929] If we got an error, it is probably because the index was bad
287
// (typically a corrupt node that confused SearchNode). Invalidate the node
288
// so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
289
// sources call this InvalidateNode.
291
(void) TrashNode(btreePtr, &nodeRec);
295
// Get the child pointer out of this index node. We're now done with the current
296
// node and can continue the search with the child node.
297
curNodeNum = *(UInt32 *)dataPtr;
298
err = ReleaseNode (btreePtr, &nodeRec);
304
// The child node should be at a level one less than the parent.
308
*nodeNum = curNodeNum;
310
*returnIndex = index;
313
return noErr; // searchKey found, index identifies record in node
315
return fsBTRecordNotFoundErr; // searchKey not found, index identifies insert point
318
(void) ReleaseNode(btreePtr, &nodeRec);
319
// fall into ErrorExit
324
nodePtr->buffer = nil;
325
nodePtr->blockHeader = nil;
334
////////////////////////////////// InsertTree ///////////////////////////////////
336
OSStatus InsertTree ( BTreeControlBlockPtr btreePtr,
337
TreePathTable treePathTable,
341
BlockDescriptor *targetNode,
344
Boolean replacingKey,
347
InsertKey primaryKey;
350
primaryKey.keyPtr = keyPtr;
351
primaryKey.keyLength = GetKeyLength(btreePtr, primaryKey.keyPtr, (level == 1));
352
primaryKey.recPtr = recPtr;
353
primaryKey.recSize = recSize;
354
primaryKey.replacingKey = replacingKey;
355
primaryKey.skipRotate = false;
357
err = InsertLevel (btreePtr, treePathTable, &primaryKey, nil,
358
targetNode, index, level, insertNode );
362
} // End of InsertTree
365
////////////////////////////////// InsertLevel //////////////////////////////////
367
OSStatus InsertLevel (BTreeControlBlockPtr btreePtr,
368
TreePathTable treePathTable,
369
InsertKey *primaryKey,
370
InsertKey *secondaryKey,
371
BlockDescriptor *targetNode,
377
BlockDescriptor siblingNode;
378
UInt32 targetNodeNum;
381
Boolean insertParent;
382
Boolean updateParent;
385
#if defined(applec) && !defined(__SC__)
386
PanicIf ((level == 1) && (((NodeDescPtr)targetNode->buffer)->kind != kBTLeafNode), "\P InsertLevel: non-leaf at level 1! ");
388
siblingNode.buffer = nil;
389
targetNodeNum = treePathTable [level].node;
391
insertParent = false;
392
updateParent = false;
394
////// process first insert //////
396
err = InsertNode (btreePtr, primaryKey, targetNode, targetNodeNum, index,
397
&newNodeNum, &newIndex, &siblingNode, &updateParent, &insertParent, &newRoot );
402
// Extend the treePathTable by adding an entry for the new
403
// root node that references the current targetNode.
405
// When we split right the index in the new root is 0 if the new
406
// node is the same as the target node or 1 otherwise. When the
407
// new node number and the target node number are the same then
408
// we inserted the new record into the left node (the orignial target)
411
treePathTable [level + 1].node = btreePtr->rootNode;
412
if ( targetNodeNum == newNodeNum )
413
treePathTable [level + 1].index = 0; //
415
treePathTable [level + 1].index = 1;
419
*insertNode = newNodeNum;
421
////// process second insert (if any) //////
423
if ( secondaryKey != nil )
427
// NOTE - we only get here if we have split a child node to the right and
428
// we are currently updating the child's parent. newIndex + 1 refers to
429
// the location in the parent node where we insert the new index record that
430
// represents the new child node (the new right node).
431
err = InsertNode (btreePtr, secondaryKey, targetNode, newNodeNum, newIndex + 1,
432
&newNodeNum, &newIndex, &siblingNode, &updateParent, &insertParent, &temp);
435
if ( DEBUG_BUILD && updateParent && newRoot )
436
DebugStr("InsertLevel: New root from primary key, update from secondary key...");
439
//////////////////////// Update Parent(s) ///////////////////////////////
441
if ( insertParent || updateParent )
443
BlockDescriptor parentNode;
444
UInt32 parentNodeNum;
451
PanicIf ( (level == btreePtr->treeDepth), "InsertLevel: unfinished insert!?");
455
// Get Parent Node data...
456
index = treePathTable [level].index;
457
parentNodeNum = treePathTable [level].node;
459
PanicIf ( parentNodeNum == 0, "InsertLevel: parent node is zero!?");
461
err = GetNode (btreePtr, parentNodeNum, &parentNode); // released as target node in next level up
463
#if defined(applec) && !defined(__SC__)
464
if (DEBUG_BUILD && level > 1)
465
PanicIf ( ((NodeDescPtr)parentNode.buffer)->kind != kBTIndexNode, "\P InsertLevel: parent node not an index node! ");
467
////////////////////////// Update Parent Index //////////////////////////////
471
//���debug: check if ptr == targetNodeNum
472
GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize);
473
PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "InsertLevel: parent ptr doesn't match target node!");
475
// need to delete and re-insert this parent key/ptr
476
// we delete it here and it gets re-inserted in the
477
// InsertLevel call below.
478
DeleteRecord (btreePtr, parentNode.buffer, index);
480
primaryKey->keyPtr = (KeyPtr) GetRecordAddress( btreePtr, targetNode->buffer, 0 );
481
primaryKey->keyLength = GetKeyLength(btreePtr, primaryKey->keyPtr, false);
482
primaryKey->recPtr = (UInt8 *) &targetNodeNum;
483
primaryKey->recSize = sizeof(targetNodeNum);
484
primaryKey->replacingKey = kReplaceRecord;
485
primaryKey->skipRotate = insertParent; // don't rotate left if we have two inserts occuring
488
////////////////////////// Add New Parent Index /////////////////////////////
492
InsertKey *insertKeyPtr;
497
insertKeyPtr = &insertKey;
498
secondaryKey = &insertKey;
502
insertKeyPtr = primaryKey;
503
// split right but not updating parent for our left node then
504
// we want to insert the key for the new right node just after
505
// the key for our left node.
509
insertKeyPtr->keyPtr = (KeyPtr) GetRecordAddress (btreePtr, siblingNode.buffer, 0);
510
insertKeyPtr->keyLength = GetKeyLength(btreePtr, insertKeyPtr->keyPtr, false);
511
insertKeyPtr->recPtr = (UInt8 *) &((NodeDescPtr)targetNode->buffer)->fLink;
512
insertKeyPtr->recSize = sizeof(UInt32);
513
insertKeyPtr->replacingKey = kInsertRecord;
514
insertKeyPtr->skipRotate = false; // a rotate is OK during second insert
517
err = InsertLevel (btreePtr, treePathTable, primaryKey, secondaryKey,
518
&parentNode, index, level, insertNode );
522
err = UpdateNode (btreePtr, targetNode); // all done with target
525
err = UpdateNode (btreePtr, &siblingNode); // all done with left sibling
532
(void) ReleaseNode (btreePtr, targetNode);
533
(void) ReleaseNode (btreePtr, &siblingNode);
535
Panic ("InsertLevel: an error occured!");
539
} // End of InsertLevel
543
////////////////////////////////// InsertNode ///////////////////////////////////
545
static OSErr InsertNode (BTreeControlBlockPtr btreePtr,
548
BlockDescriptor *targetNode,
552
UInt32 *newNodeNumPtr,
555
BlockDescriptor *siblingNode,
556
Boolean *updateParent,
557
Boolean *insertParent,
560
BlockDescriptor *tempNode;
569
PanicIf ( targetNode->buffer == siblingNode->buffer, "InsertNode: targetNode == siblingNode, huh?");
571
leftNodeNum = ((NodeDescPtr) targetNode->buffer)->bLink;
572
rightNodeNum = ((NodeDescPtr) targetNode->buffer)->fLink;
575
/////////////////////// Try Simple Insert ///////////////////////////////
577
if ( nodeNum == leftNodeNum )
578
tempNode = siblingNode;
580
tempNode = targetNode;
582
recordFit = InsertKeyRecord (btreePtr, tempNode->buffer, index, key->keyPtr, key->keyLength, key->recPtr, key->recSize);
586
*newNodeNumPtr = nodeNum;
590
if ( DoKeyCheck( tempNode->buffer, btreePtr ) != noErr )
592
printf( "\n%s - bad key order in node num %d: \n", __FUNCTION__ , nodeNum );
593
PrintNodeDescriptor( tempNode->buffer );
594
err = fsBTBadRotateErr;
597
#endif // DEBUG_TREEOPS
599
if ( (index == 0) && (((NodeDescPtr) tempNode->buffer)->height != btreePtr->treeDepth) )
600
*updateParent = true; // the first record changed so we need to update the parent
601
goto ExitThisRoutine;
605
//////////////////////// Try Rotate Left ////////////////////////////////
607
if ( leftNodeNum > 0 )
609
PanicIf ( siblingNode->buffer != nil, "InsertNode: siblingNode already aquired!");
611
if ( siblingNode->buffer == nil )
613
err = GetNode (btreePtr, leftNodeNum, siblingNode); // will be released by caller or a split below
617
PanicIf ( ((NodeDescPtr) siblingNode->buffer)->fLink != nodeNum, "InsertNode, RotateLeft: invalid sibling link!" );
619
if ( !key->skipRotate ) // are rotates allowed?
621
err = RotateLeft (btreePtr, siblingNode->buffer, targetNode->buffer, index, key->keyPtr, key->recPtr,
622
key->recSize, newIndex, newNodeNumPtr, &recordFit, &recsRotated );
627
if ( key->replacingKey || (recsRotated > 1) || (index > 0) )
628
*updateParent = true;
629
goto ExitThisRoutine;
635
//////////////////////// Try Split Right /////////////////////////////////
637
(void) ReleaseNode( btreePtr, siblingNode );
638
err = SplitRight( btreePtr, targetNode, siblingNode, nodeNum, index, key->keyPtr,
639
key->recPtr, key->recSize, newIndex, newNodeNumPtr, &recsRotated );
642
// if we split root node - add new root
643
if ( ((NodeDescPtr) targetNode->buffer)->height == btreePtr->treeDepth )
645
err = AddNewRootNode( btreePtr, targetNode->buffer, siblingNode->buffer ); // Note: does not update TPT
651
*insertParent = true;
653
// update parent index node when replacingKey is true or when
654
// we inserted a new record at the beginning of our target node.
655
if ( key->replacingKey || ( index == 0 && *newIndex == 0 ) )
656
*updateParent = true;
665
(void) ReleaseNode (btreePtr, siblingNode);
668
} // End of InsertNode
671
/*-------------------------------------------------------------------------------
672
Routine: DeleteTree - One_line_description.
674
Function: Brief_description_of_the_function_and_any_side_effects
678
Input: btreePtr - description
679
treePathTable - description
680
targetNode - description
683
Result: noErr - success
685
-------------------------------------------------------------------------------*/
687
OSStatus DeleteTree (BTreeControlBlockPtr btreePtr,
688
TreePathTable treePathTable,
689
BlockDescriptor *targetNode,
694
BlockDescriptor parentNode;
695
BTNodeDescriptor *targetNodePtr;
696
UInt32 targetNodeNum;
697
Boolean deleteRequired;
698
Boolean updateRequired;
701
deleteRequired = false;
702
updateRequired = false;
704
targetNodeNum = treePathTable[level].node;
705
targetNodePtr = targetNode->buffer;
706
PanicIf (targetNodePtr == nil, "DeleteTree: targetNode has nil buffer!");
708
DeleteRecord (btreePtr, targetNodePtr, index);
710
//�� coalesce remaining records?
712
if ( targetNodePtr->numRecords == 0 ) // did we delete the last record?
714
BlockDescriptor siblingNode;
715
UInt32 siblingNodeNum;
717
deleteRequired = true;
719
////////////////// Get Siblings & Update Links //////////////////////////
721
siblingNodeNum = targetNodePtr->bLink; // Left Sibling Node
722
if ( siblingNodeNum != 0 )
724
err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
726
((NodeDescPtr)siblingNode.buffer)->fLink = targetNodePtr->fLink;
727
err = UpdateNode (btreePtr, &siblingNode);
730
else if ( targetNodePtr->kind == kBTLeafNode ) // update firstLeafNode
732
btreePtr->firstLeafNode = targetNodePtr->fLink;
735
siblingNodeNum = targetNodePtr->fLink; // Right Sibling Node
736
if ( siblingNodeNum != 0 )
738
err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
740
((NodeDescPtr)siblingNode.buffer)->bLink = targetNodePtr->bLink;
741
err = UpdateNode (btreePtr, &siblingNode);
744
else if ( targetNodePtr->kind == kBTLeafNode ) // update lastLeafNode
746
btreePtr->lastLeafNode = targetNodePtr->bLink;
749
//////////////////////// Free Empty Node ////////////////////////////////
751
ClearNode (btreePtr, targetNodePtr);
753
err = UpdateNode (btreePtr, targetNode);
755
err = FreeNode (btreePtr, targetNodeNum);
758
else if ( index == 0 ) // did we delete the first record?
760
updateRequired = true; // yes, so we need to update parent
764
if ( level == btreePtr->treeDepth ) // then targetNode->buffer is the root node
766
deleteRequired = false;
767
updateRequired = false;
769
if ( targetNode->buffer == nil ) // then root was freed and the btree is empty
771
btreePtr->rootNode = 0;
772
btreePtr->treeDepth = 0;
774
else if ( ((NodeDescPtr)targetNode->buffer)->numRecords == 1 )
776
err = CollapseTree (btreePtr, targetNode);
782
if ( updateRequired || deleteRequired )
784
++level; // next level
786
//// Get Parent Node and index
787
index = treePathTable [level].index;
788
err = GetNode (btreePtr, treePathTable[level].node, &parentNode);
791
if ( updateRequired )
798
//���debug: check if ptr == targetNodeNum
799
GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize);
800
PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, " DeleteTree: parent ptr doesn't match targetNodeNum!!");
802
// need to delete and re-insert this parent key/ptr
803
DeleteRecord (btreePtr, parentNode.buffer, index);
805
keyPtr = (KeyPtr) GetRecordAddress( btreePtr, targetNode->buffer, 0 );
806
recPtr = (UInt8 *) &targetNodeNum;
807
recSize = sizeof(targetNodeNum);
809
err = InsertTree (btreePtr, treePathTable, keyPtr, recPtr, recSize,
810
&parentNode, index, level, kReplaceRecord, &insertNode);
813
else // deleteRequired
815
err = DeleteTree (btreePtr, treePathTable, &parentNode, index, level);
821
err = UpdateNode (btreePtr, targetNode);
828
(void) ReleaseNode (btreePtr, targetNode);
829
(void) ReleaseNode (btreePtr, &parentNode);
837
///////////////////////////////// CollapseTree //////////////////////////////////
839
static OSStatus CollapseTree (BTreeControlBlockPtr btreePtr,
840
BlockDescriptor *blockPtr )
846
originalRoot = btreePtr->rootNode;
850
if ( ((NodeDescPtr)blockPtr->buffer)->numRecords > 1)
851
break; // this will make a fine root node
853
if ( ((NodeDescPtr)blockPtr->buffer)->kind == kBTLeafNode)
854
break; // we've hit bottom
856
nodeNum = btreePtr->rootNode;
857
btreePtr->rootNode = GetChildNodeNum (btreePtr, blockPtr->buffer, 0);
858
--btreePtr->treeDepth;
860
//// Clear and Free Current Old Root Node ////
861
ClearNode (btreePtr, blockPtr->buffer);
862
err = UpdateNode (btreePtr, blockPtr);
864
err = FreeNode (btreePtr, nodeNum);
867
//// Get New Root Node
868
err = GetNode (btreePtr, btreePtr->rootNode, blockPtr);
872
if (btreePtr->rootNode != originalRoot)
873
M_BTreeHeaderDirty (btreePtr);
875
err = UpdateNode (btreePtr, blockPtr); // always update!
881
/////////////////////////////////// ErrorExit ///////////////////////////////////
884
(void) ReleaseNode (btreePtr, blockPtr);
890
////////////////////////////////// RotateLeft ///////////////////////////////////
892
/*-------------------------------------------------------------------------------
894
Routine: RotateLeft - One_line_description.
896
Function: Brief_description_of_the_function_and_any_side_effects
898
Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
900
Input: btreePtr - description
901
leftNode - description
902
rightNode - description
903
rightInsertIndex - description
906
recSize - description
909
insertNodeNum - description
910
recordFit - description
913
Result: noErr - success
915
-------------------------------------------------------------------------------*/
917
static OSStatus RotateLeft (BTreeControlBlockPtr btreePtr,
918
NodeDescPtr leftNode,
919
NodeDescPtr rightNode,
920
UInt16 rightInsertIndex,
925
UInt32 *insertNodeNum,
927
UInt16 *recsRotated )
932
SInt32 leftSize, rightSize;
935
UInt16 lengthFieldSize;
936
UInt16 index, moveIndex;
939
///////////////////// Determine If Record Will Fit //////////////////////////
941
keyLength = GetKeyLength(btreePtr, keyPtr, (rightNode->kind == kBTLeafNode));
943
// the key's length field is 8-bits in HFS and 16-bits in HFS+
944
if ( btreePtr->attributes & kBTBigKeysMask )
945
lengthFieldSize = sizeof(UInt16);
947
lengthFieldSize = sizeof(UInt8);
949
insertSize = keyLength + lengthFieldSize + recSize + sizeof(UInt16);
951
if ( M_IsOdd (insertSize) )
952
++insertSize; // add pad byte;
954
nodeSize = btreePtr->nodeSize;
956
// add size of insert record to right node
957
rightSize = nodeSize - GetNodeFreeSize (btreePtr, rightNode) + insertSize;
958
leftSize = nodeSize - GetNodeFreeSize (btreePtr, leftNode);
963
while ( leftSize < rightSize )
965
if ( moveIndex < rightInsertIndex )
967
moveSize = GetRecordSize (btreePtr, rightNode, moveIndex) + 2;
969
else if ( moveIndex == rightInsertIndex )
971
moveSize = insertSize;
973
else // ( moveIndex > rightInsertIndex )
975
moveSize = GetRecordSize (btreePtr, rightNode, moveIndex - 1) + 2;
978
leftSize += moveSize;
979
rightSize -= moveSize;
983
if ( leftSize > nodeSize ) // undo last move
985
leftSize -= moveSize;
986
rightSize += moveSize;
990
if ( rightSize > nodeSize ) // record won't fit - failure, but not error
1000
// we've found balance point, moveIndex == number of records moved into leftNode
1003
//////////////////////////// Rotate Records /////////////////////////////////
1005
*recsRotated = moveIndex;
1009
while ( index < moveIndex )
1011
if ( index == rightInsertIndex ) // insert new record in left node
1013
UInt16 leftInsertIndex;
1015
leftInsertIndex = leftNode->numRecords;
1017
didItFit = InsertKeyRecord (btreePtr, leftNode, leftInsertIndex,
1018
keyPtr, keyLength, recPtr, recSize);
1021
Panic ("RotateLeft: InsertKeyRecord (left) returned false!");
1022
err = fsBTBadRotateErr;
1026
*insertIndex = leftInsertIndex;
1027
*insertNodeNum = rightNode->bLink;
1031
didItFit = RotateRecordLeft (btreePtr, leftNode, rightNode);
1034
Panic ("RotateLeft: RotateRecordLeft returned false!");
1035
err = fsBTBadRotateErr;
1043
if ( moveIndex <= rightInsertIndex ) // then insert new record in right node
1045
rightInsertIndex -= index; // adjust for records already rotated
1047
didItFit = InsertKeyRecord (btreePtr, rightNode, rightInsertIndex,
1048
keyPtr, keyLength, recPtr, recSize);
1051
Panic ("RotateLeft: InsertKeyRecord (right) returned false!");
1052
err = fsBTBadRotateErr;
1056
*insertIndex = rightInsertIndex;
1057
*insertNodeNum = leftNode->fLink;
1061
if ( DoKeyCheck( leftNode, btreePtr ) != noErr )
1063
printf( "\n%s - bad key order in left node num %d: \n", __FUNCTION__ , rightNode->bLink );
1064
PrintNodeDescriptor( leftNode );
1065
err = fsBTBadRotateErr;
1068
if ( DoKeyCheck( rightNode, btreePtr ) != noErr )
1070
printf( "\n%s - bad key order in left node num %d: \n", __FUNCTION__ , leftNode->fLink );
1071
PrintNodeDescriptor( rightNode );
1072
err = fsBTBadRotateErr;
1075
#endif // DEBUG_TREEOPS
1081
////////////////////////////// Error Exit ///////////////////////////////////
1095
/////////////////////////////////// SplitLeft ///////////////////////////////////
1097
static OSStatus SplitLeft (BTreeControlBlockPtr btreePtr,
1098
BlockDescriptor *leftNode,
1099
BlockDescriptor *rightNode,
1100
UInt32 rightNodeNum,
1105
UInt16 *insertIndex,
1106
UInt32 *insertNodeNum,
1107
UInt16 *recsRotated )
1110
NodeDescPtr left, right;
1115
///////////////////////////// Compare Nodes /////////////////////////////////
1117
right = rightNode->buffer;
1118
left = leftNode->buffer;
1120
PanicIf ( right->bLink != 0 && left == 0, " SplitLeft: left sibling missing!?" );
1122
//�� type should be kLeafNode or kIndexNode
1124
if ( (right->height == 1) && (right->kind != kBTLeafNode) )
1125
return fsBTInvalidNodeErr;
1129
if ( left->fLink != rightNodeNum )
1130
return fsBTInvalidNodeErr; //�� E_BadSibling ?
1132
if ( left->height != right->height )
1133
return fsBTInvalidNodeErr; //�� E_BadNodeHeight ?
1135
if ( left->kind != right->kind )
1136
return fsBTInvalidNodeErr; //�� E_BadNodeType ?
1140
///////////////////////////// Allocate Node /////////////////////////////////
1142
err = AllocateNode (btreePtr, &newNodeNum);
1143
M_ExitOnError (err);
1146
/////////////// Update Forward Link In Original Left Node ///////////////////
1150
left->fLink = newNodeNum;
1151
err = UpdateNode (btreePtr, leftNode);
1152
M_ExitOnError (err);
1156
/////////////////////// Initialize New Left Node ////////////////////////////
1158
err = GetNewNode (btreePtr, newNodeNum, leftNode);
1159
M_ExitOnError (err);
1161
left = leftNode->buffer;
1162
left->fLink = rightNodeNum;
1165
// Steal Info From Right Node
1167
left->bLink = right->bLink;
1168
left->kind = right->kind;
1169
left->height = right->height;
1171
right->bLink = newNodeNum; // update Right bLink
1173
if ( (left->kind == kBTLeafNode) && (left->bLink == 0) )
1175
// if we're adding a new first leaf node - update BTreeInfoRec
1177
btreePtr->firstLeafNode = newNodeNum;
1178
M_BTreeHeaderDirty (btreePtr); //�� AllocateNode should have set the bit already...
1181
////////////////////////////// Rotate Left //////////////////////////////////
1183
err = RotateLeft (btreePtr, left, right, index, keyPtr, recPtr, recSize,
1184
insertIndex, insertNodeNum, &recordFit, recsRotated);
1185
M_ExitOnError (err);
1191
(void) ReleaseNode (btreePtr, leftNode);
1192
(void) ReleaseNode (btreePtr, rightNode);
1194
//�� Free new node if allocated?
1206
/////////////////////////////// RotateRecordLeft ////////////////////////////////
1208
static Boolean RotateRecordLeft (BTreeControlBlockPtr btreePtr,
1209
NodeDescPtr leftNode,
1210
NodeDescPtr rightNode )
1216
size = GetRecordSize (btreePtr, rightNode, 0);
1217
recPtr = GetRecordAddress (btreePtr, rightNode, 0);
1219
recordFit = InsertRecord (btreePtr, leftNode, leftNode->numRecords, recPtr, size);
1224
DeleteRecord (btreePtr, rightNode, 0);
1230
//////////////////////////////// AddNewRootNode /////////////////////////////////
1232
static OSStatus AddNewRootNode (BTreeControlBlockPtr btreePtr,
1233
NodeDescPtr leftNode,
1234
NodeDescPtr rightNode )
1237
BlockDescriptor rootNode;
1243
PanicIf (leftNode == nil, "AddNewRootNode: leftNode == nil");
1244
PanicIf (rightNode == nil, "AddNewRootNode: rightNode == nil");
1247
/////////////////////// Initialize New Root Node ////////////////////////////
1249
err = AllocateNode (btreePtr, &rootNum);
1250
M_ExitOnError (err);
1252
err = GetNewNode (btreePtr, rootNum, &rootNode);
1253
M_ExitOnError (err);
1255
((NodeDescPtr)rootNode.buffer)->kind = kBTIndexNode;
1256
((NodeDescPtr)rootNode.buffer)->height = ++btreePtr->treeDepth;
1259
///////////////////// Insert Left Node Index Record /////////////////////////
1261
keyPtr = (KeyPtr) GetRecordAddress (btreePtr, leftNode, 0);
1262
keyLength = GetKeyLength(btreePtr, keyPtr, false);
1264
didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 0, keyPtr, keyLength,
1265
(UInt8 *) &rightNode->bLink, 4 );
1267
PanicIf ( !didItFit, "AddNewRootNode:InsertKeyRecord failed for left index record");
1270
//////////////////// Insert Right Node Index Record /////////////////////////
1272
keyPtr = (KeyPtr) GetRecordAddress (btreePtr, rightNode, 0);
1273
keyLength = GetKeyLength(btreePtr, keyPtr, false);
1275
didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 1, keyPtr, keyLength,
1276
(UInt8 *) &leftNode->fLink, 4 );
1278
PanicIf ( !didItFit, "AddNewRootNode:InsertKeyRecord failed for right index record");
1282
if ( DoKeyCheck( rootNode.buffer, btreePtr ) != noErr )
1284
printf( "\n%s - bad key order in root node num %d: \n", __FUNCTION__ , rootNum );
1285
PrintNodeDescriptor( rootNode.buffer );
1286
err = fsBTBadRotateErr;
1289
#endif // DEBUG_TREEOPS
1292
/////////////////////////// Release Root Node ///////////////////////////////
1294
err = UpdateNode (btreePtr, &rootNode);
1295
M_ExitOnError (err);
1297
// update BTreeInfoRec
1299
btreePtr->rootNode = rootNum;
1300
btreePtr->flags |= kBTHeaderDirty;
1305
////////////////////////////// Error Exit ///////////////////////////////////
1313
static UInt16 GetKeyLength ( const BTreeControlBlock *btreePtr, const BTreeKey *key, Boolean forLeafNode )
1317
if ( forLeafNode || btreePtr->attributes & kBTVariableIndexKeysMask )
1318
length = KeyLength (btreePtr, key); // just use actual key length
1320
length = btreePtr->maxKeyLength; // fixed sized index key (i.e. HFS) //�� shouldn't we clear the pad bytes?
1327
/////////////////////////////////// SplitRight ///////////////////////////////////
1329
static OSStatus SplitRight (BTreeControlBlockPtr btreePtr,
1330
BlockDescriptor *nodePtr,
1331
BlockDescriptor *rightNodePtr,
1337
UInt16 *insertIndexPtr,
1338
UInt32 *newNodeNumPtr,
1339
UInt16 *recsRotatedPtr )
1342
NodeDescPtr leftPtr, rightPtr;
1347
///////////////////////////// Compare Nodes /////////////////////////////////
1349
leftPtr = nodePtr->buffer;
1351
if ( leftPtr->fLink != 0 )
1353
err = GetNode( btreePtr, leftPtr->fLink, rightNodePtr );
1354
M_ExitOnError( err );
1356
rightPtr = rightNodePtr->buffer;
1358
PanicIf ( leftPtr->fLink != 0 && rightPtr == 0, "SplitRight: right sibling missing!?" );
1360
//�� type should be kLeafNode or kIndexNode
1362
if ( (leftPtr->height == 1) && (leftPtr->kind != kBTLeafNode) )
1363
return fsBTInvalidNodeErr;
1365
if ( rightPtr != nil )
1367
if ( rightPtr->bLink != nodeNum )
1368
return fsBTInvalidNodeErr; //�� E_BadSibling ?
1370
if ( rightPtr->height != leftPtr->height )
1371
return fsBTInvalidNodeErr; //�� E_BadNodeHeight ?
1373
if ( rightPtr->kind != leftPtr->kind )
1374
return fsBTInvalidNodeErr; //�� E_BadNodeType ?
1378
///////////////////////////// Allocate Node /////////////////////////////////
1380
err = AllocateNode (btreePtr, &newNodeNum);
1381
M_ExitOnError (err);
1383
/////////////// Update backward Link In Original Right Node ///////////////////
1385
if ( rightPtr != nil )
1387
rightPtr->bLink = newNodeNum;
1388
err = UpdateNode (btreePtr, rightNodePtr);
1389
M_ExitOnError (err);
1392
/////////////////////// Initialize New Right Node ////////////////////////////
1394
err = GetNewNode (btreePtr, newNodeNum, rightNodePtr );
1395
M_ExitOnError (err);
1397
rightPtr = rightNodePtr->buffer;
1398
rightPtr->bLink = nodeNum;
1401
// Steal Info From Left Node
1403
rightPtr->fLink = leftPtr->fLink;
1404
rightPtr->kind = leftPtr->kind;
1405
rightPtr->height = leftPtr->height;
1407
leftPtr->fLink = newNodeNum; // update Left fLink
1409
if ( (rightPtr->kind == kBTLeafNode) && (rightPtr->fLink == 0) )
1411
// if we're adding a new last leaf node - update BTreeInfoRec
1413
btreePtr->lastLeafNode = newNodeNum;
1414
M_BTreeHeaderDirty (btreePtr); //�� AllocateNode should have set the bit already...
1417
////////////////////////////// Rotate Right //////////////////////////////////
1419
err = RotateRight (btreePtr, leftPtr, rightPtr, index, keyPtr, recPtr, recSize,
1420
insertIndexPtr, newNodeNumPtr, &recordFit, recsRotatedPtr);
1421
M_ExitOnError (err);
1427
(void) ReleaseNode (btreePtr, nodePtr);
1428
(void) ReleaseNode (btreePtr, rightNodePtr);
1430
//�� Free new node if allocated?
1432
*insertIndexPtr = 0;
1434
*recsRotatedPtr = 0;
1442
////////////////////////////////// RotateRight ///////////////////////////////////
1444
/*-------------------------------------------------------------------------------
1446
Routine: RotateRight - rotate half of .
1448
Function: Brief_description_of_the_function_and_any_side_effects
1450
Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
1452
Input: btreePtr - description
1453
leftNode - description
1454
rightNode - description
1455
leftInsertIndex - description
1456
keyPtr - description
1457
recPtr - description
1458
recSize - description
1461
insertNodeNum - description
1462
recordFit - description
1465
Result: noErr - success
1467
-------------------------------------------------------------------------------*/
1469
static OSStatus RotateRight (BTreeControlBlockPtr btreePtr,
1470
NodeDescPtr leftNodePtr,
1471
NodeDescPtr rightNodePtr,
1472
UInt16 leftInsertIndex,
1476
UInt16 *insertIndexPtr,
1477
UInt32 *newNodeNumPtr,
1478
Boolean *didRecordFitPtr,
1479
UInt16 *recsRotatedPtr )
1484
SInt32 leftSize, rightSize;
1487
UInt16 lengthFieldSize;
1488
SInt16 index, moveIndex, myInsertIndex;
1490
Boolean doIncrement = false;
1492
///////////////////// Determine If Record Will Fit //////////////////////////
1494
keyLength = GetKeyLength( btreePtr, keyPtr, (leftNodePtr->kind == kBTLeafNode) );
1496
// the key's length field is 8-bits in HFS and 16-bits in HFS+
1497
if ( btreePtr->attributes & kBTBigKeysMask )
1498
lengthFieldSize = sizeof(UInt16);
1500
lengthFieldSize = sizeof(UInt8);
1502
insertSize = keyLength + lengthFieldSize + recSize + sizeof(UInt16);
1503
if ( M_IsOdd (insertSize) )
1504
++insertSize; // add pad byte;
1505
nodeSize = btreePtr->nodeSize;
1507
// add size of insert record to left node
1508
rightSize = nodeSize - GetNodeFreeSize( btreePtr, rightNodePtr );
1509
leftSize = nodeSize - GetNodeFreeSize( btreePtr, leftNodePtr ) + insertSize;
1511
moveIndex = leftNodePtr->numRecords - 1; // start at last record in the node
1514
while ( rightSize < leftSize )
1516
moveSize = GetRecordSize( btreePtr, leftNodePtr, moveIndex ) + 2;
1518
if ( moveIndex == leftInsertIndex || leftNodePtr->numRecords == leftInsertIndex )
1519
moveSize += insertSize;
1521
leftSize -= moveSize;
1522
rightSize += moveSize;
1526
if ( rightSize > nodeSize ) // undo last move
1528
leftSize += moveSize;
1529
rightSize -= moveSize;
1533
if ( leftSize > nodeSize ) // record won't fit - failure, but not error
1535
*insertIndexPtr = 0;
1537
*didRecordFitPtr = false;
1538
*recsRotatedPtr = 0;
1543
// we've found balance point,
1545
//////////////////////////// Rotate Records /////////////////////////////////
1547
*didRecordFitPtr = true;
1548
index = leftNodePtr->numRecords - 1;
1549
*recsRotatedPtr = index - moveIndex;
1552
// handle case where the new record is inserting after the last
1553
// record in our left node.
1554
if ( leftNodePtr->numRecords == leftInsertIndex )
1556
didItFit = InsertKeyRecord (btreePtr, rightNodePtr, 0,
1557
keyPtr, keyLength, recPtr, recSize);
1560
Panic ("RotateRight: InsertKeyRecord (left) returned false!");
1561
err = fsBTBadRotateErr;
1565
// NOTE - our insert location will slide as we insert more records
1567
*newNodeNumPtr = leftNodePtr->fLink;
1570
while ( index > moveIndex )
1572
didItFit = RotateRecordRight( btreePtr, leftNodePtr, rightNodePtr );
1575
Panic ("RotateRight: RotateRecordRight returned false!");
1576
err = fsBTBadRotateErr;
1580
if ( index == leftInsertIndex ) // insert new record in right node
1582
didItFit = InsertKeyRecord (btreePtr, rightNodePtr, 0,
1583
keyPtr, keyLength, recPtr, recSize);
1586
Panic ("RotateRight: InsertKeyRecord (left) returned false!");
1587
err = fsBTBadRotateErr;
1591
// NOTE - our insert index will slide as we insert more records
1594
*newNodeNumPtr = leftNodePtr->fLink;
1602
*insertIndexPtr = myInsertIndex;
1604
if ( moveIndex >= leftInsertIndex ) // then insert new record in left node
1606
didItFit = InsertKeyRecord (btreePtr, leftNodePtr, leftInsertIndex,
1607
keyPtr, keyLength, recPtr, recSize);
1610
Panic ("RotateRight: InsertKeyRecord (right) returned false!");
1611
err = fsBTBadRotateErr;
1615
*insertIndexPtr = leftInsertIndex;
1616
*newNodeNumPtr = rightNodePtr->bLink;
1620
if ( DoKeyCheck( rightNodePtr, btreePtr ) != noErr )
1622
printf( "\n%s - bad key order in right node num %d: \n", __FUNCTION__ , leftNodePtr->fLink);
1623
PrintNodeDescriptor( rightNodePtr );
1624
err = fsBTBadRotateErr;
1627
if ( DoKeyCheck( leftNodePtr, btreePtr ) != noErr )
1629
printf( "\n%s - bad key order in left node num %d: \n", __FUNCTION__ , rightNodePtr->bLink);
1630
PrintNodeDescriptor( leftNodePtr );
1631
err = fsBTBadRotateErr;
1634
if ( DoKeyCheckAcrossNodes( leftNodePtr, rightNodePtr, btreePtr, false ) != noErr )
1636
printf( "\n%s - bad key order across nodes left %d right %d: \n",
1637
__FUNCTION__ , rightNodePtr->bLink, leftNodePtr->fLink );
1638
PrintNodeDescriptor( leftNodePtr );
1639
PrintNodeDescriptor( rightNodePtr );
1640
err = fsBTBadRotateErr;
1643
#endif // DEBUG_TREEOPS
1648
////////////////////////////// Error Exit ///////////////////////////////////
1652
*insertIndexPtr = 0;
1654
*didRecordFitPtr = false;
1655
*recsRotatedPtr = 0;
1663
/////////////////////////////// RotateRecordRight ////////////////////////////////
1665
static Boolean RotateRecordRight (BTreeControlBlockPtr btreePtr,
1666
NodeDescPtr leftNodePtr,
1667
NodeDescPtr rightNodePtr )
1671
Boolean didRecordFit;
1673
size = GetRecordSize( btreePtr, leftNodePtr, leftNodePtr->numRecords - 1 ) ;
1674
recPtr = GetRecordAddress( btreePtr, leftNodePtr, leftNodePtr->numRecords - 1 ) ;
1676
didRecordFit = InsertRecord( btreePtr, rightNodePtr, 0, recPtr, size );
1677
if ( !didRecordFit )
1680
DeleteRecord( btreePtr, leftNodePtr, leftNodePtr->numRecords - 1 );
1684
} /* RotateRecordRight */
1689
static int DoKeyCheckAcrossNodes( NodeDescPtr theLeftNodePtr,
1690
NodeDescPtr theRightNodePtr,
1691
BTreeControlBlock *theTreePtr,
1694
UInt16 myLeftDataSize;
1695
UInt16 myRightDataSize;
1696
UInt16 myRightKeyLen;
1697
UInt16 myLeftKeyLen;
1698
KeyPtr myLeftKeyPtr;
1699
KeyPtr myRightKeyPtr;
1700
UInt8 * myLeftDataPtr;
1701
UInt8 * myRightDataPtr;
1704
GetRecordByIndex( theTreePtr, theLeftNodePtr, (theLeftNodePtr->numRecords - 1),
1705
&myLeftKeyPtr, &myLeftDataPtr, &myLeftDataSize );
1706
GetRecordByIndex( theTreePtr, theRightNodePtr, 0,
1707
&myRightKeyPtr, &myRightDataPtr, &myRightDataSize );
1709
if ( theTreePtr->attributes & kBTBigKeysMask )
1711
myRightKeyLen = myRightKeyPtr->length16;
1712
myLeftKeyLen = myLeftKeyPtr->length16;
1716
myRightKeyLen = myRightKeyPtr->length8;
1717
myLeftKeyLen = myLeftKeyPtr->length8;
1722
printf( "%s - left and right keys:\n", __FUNCTION__ );
1723
PrintKey( (UInt8 *) myLeftKeyPtr, myLeftKeyLen );
1724
PrintKey( (UInt8 *) myRightKeyPtr, myRightKeyLen );
1727
if ( CompareKeys( theTreePtr, myLeftKeyPtr, myRightKeyPtr ) >= 0 )
1732
} /* DoKeyCheckAcrossNodes */
1735
static int DoKeyCheck( NodeDescPtr nodeP, BTreeControlBlock *btcb )
1742
KeyPtr prevkeyP = nil;
1745
if ( nodeP->numRecords == 0 )
1747
if ( (nodeP->fLink == 0) && (nodeP->bLink == 0) )
1753
* Loop on number of records in node
1755
for ( index = 0; index < nodeP->numRecords; index++)
1757
GetRecordByIndex( (BTreeControlBlock *)btcb, nodeP, (UInt16) index, &keyPtr, &dataPtr, &dataSize );
1759
if (btcb->attributes & kBTBigKeysMask)
1760
keyLength = keyPtr->length16;
1762
keyLength = keyPtr->length8;
1764
if ( keyLength > btcb->maxKeyLength )
1769
if ( prevkeyP != nil )
1771
if ( CompareKeys( (BTreeControlBlockPtr)btcb, prevkeyP, keyPtr ) >= 0 )
1784
static void PrintNodeDescriptor( NodeDescPtr thePtr )
1786
printf( " fLink %d bLink %d kind %d height %d numRecords %d \n",
1787
thePtr->fLink, thePtr->bLink, thePtr->kind, thePtr->height, thePtr->numRecords );
1791
static void PrintKey( UInt8 * myPtr, int mySize )
1795
for ( i = 0; i < mySize+2; i++ )
1797
printf("%02X", *(myPtr + i) );
1803
#endif // DEBUG_TREEOPS