2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 Contains: Multi-node tree operations for the BTree Module.
27 Version: xxx put the technology version here xxx
29 Written by: Gordon Sheridan and Bill Bruffey
31 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
37 Other Contact: Mark Day
39 Technology: File Systems
47 Change History (most recent first):
49 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
50 <CS5> 12/8/97 djb Radar #2200632, CollapseTree wasn't marking root node dirty.
51 <CS4> 11/24/97 djb Radar #2005325, InsertLevel incorrectly handled root splits!
52 <CS3> 10/17/97 msd Conditionalize DebugStrs.
53 <CS2> 5/16/97 msd InsertNode() needs a return statement in ErrorExit.
54 <CS1> 4/23/97 djb first checked in
56 <HFS8> 3/17/97 DSH Conditionalize out Panic assertion for SC.
57 <HFS7> 3/3/97 djb Removed DebugStr in InsertLevel.
58 <HFS6> 2/19/97 djb Major re-write of insert code; added InsertLevel and InsertNode.
59 <HFS5> 1/27/97 djb InsertTree and DeleteTree are now recursive and support variable
61 <HFS4> 1/16/97 djb Removed DebugStr in SearchTree. Added initial support for
62 variable sized index keys.
63 <HFS3> 1/3/97 djb Changed len8 to length8.
64 <HFS2> 1/3/97 djb Added support for large keys.
65 <HFS1> 12/19/96 djb first checked in
67 History applicable to original Scarecrow Design:
69 <3> 10/25/96 ser Changing for new VFPI
70 <2> 1/22/96 dkh Add #include Memory.h
71 <1> 10/18/95 rst Moved from Scarecrow project.
73 <12> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
74 <11> 9/30/94 prp Get in sync with D2 interface changes.
75 <10> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
76 <9> 7/22/94 wjk Convert to the new set of header files.
77 <8> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
79 <7> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
80 agree with their prototypes.
81 <6> 5/21/93 gs Debug DeleteTree. Modify InsertTree for BTReplaceRecord.
82 <5> 5/10/93 gs Modify RotateLeft, and add DeleteTree, CollapseTree routines.
83 <4> 3/23/93 gs revise RotateLeft to use InsertKeyRecord instead of
85 <3> 3/23/93 gs Implement SplitLeft, InsertTree routine.
86 <2> 2/8/93 gs Implement SearchTree, and RotateLeft.
87 <1> 11/15/92 gs first checked in
91 #include "../headers/BTreesPrivate.h"
94 /////////////////////// Routines Internal To BTree Module ///////////////////////
99 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
101 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
102 NodeDescPtr leftNode
,
103 NodeDescPtr rightNode
);
105 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
106 BlockDescriptor
*blockPtr
);
108 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
109 NodeDescPtr leftNode
,
110 NodeDescPtr rightNode
,
111 UInt16 rightInsertIndex
,
116 UInt32
*insertNodeNum
,
118 UInt16
*recsRotated
);
120 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
121 NodeDescPtr leftNode
,
122 NodeDescPtr rightNode
);
124 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
125 BlockDescriptor
*leftNode
,
126 BlockDescriptor
*rightNode
,
133 UInt32
*insertNodeNum
,
134 UInt16
*recsRotated
);
138 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
139 TreePathTable treePathTable
,
140 InsertKey
*primaryKey
,
141 InsertKey
*secondaryKey
,
142 BlockDescriptor
*targetNode
,
145 UInt32
*insertNode
);
147 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
149 BlockDescriptor
*rightNode
,
154 BlockDescriptor
*leftNode
,
155 Boolean
*updateParent
,
156 Boolean
*insertParent
,
157 Boolean
*rootSplit
);
159 static UInt16
GetKeyLength (const BTreeControlBlock
*btreePtr
,
161 Boolean forLeafNode
);
165 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
168 /*-------------------------------------------------------------------------------
170 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
172 Function: Searches BTree for specified key, setting up the Tree Path Table to
173 reflect the search path.
176 Input: btreePtr - pointer to control block of BTree to search
177 keyPtr - pointer to the key to search for
178 treePathTable - pointer to the tree path table to construct
180 Output: nodeNum - number of the node containing the key position
181 iterator - BTreeIterator specifying record or insert position
183 Result: noErr - key found, index is record index
184 fsBTRecordNotFoundErr - key not found, index is insert index
185 fsBTEmptyErr - key not found, return params are nil
186 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
187 -------------------------------------------------------------------------------*/
189 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
190 BTreeKeyPtr searchKey
,
191 TreePathTable treePathTable
,
193 BlockDescriptor
*nodePtr
,
194 UInt16
*returnIndex
)
207 if (btreePtr
->treeDepth
== 0) // is the tree empty?
213 curNodeNum
= btreePtr
->rootNode
;
215 //\80\80 for debugging...
216 treePathTable
[0].node
= 0;
217 treePathTable
[0].index
= 0;
221 PanicIf(curNodeNum
== 0, "\pSearchTree: curNodeNum is zero!");
223 err
= GetNode (btreePtr
, curNodeNum
, &nodeRec
);
229 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
231 level
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->height
; //\80\80 or --level;
234 treePathTable
[level
].node
= curNodeNum
;
236 if ( ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
== kBTLeafNode
)
238 treePathTable
[level
].index
= index
;
239 break; // were done...
242 if ( (keyFound
!= true) && (index
!= 0))
245 treePathTable
[level
].index
= index
;
247 GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
248 curNodeNum
= *(UInt32
*)dataPtr
;
249 err
= ReleaseNode (btreePtr
, &nodeRec
);
256 *nodeNum
= curNodeNum
;
258 *returnIndex
= index
;
261 return noErr
; // searchKey found, index identifies record in node
263 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
268 nodePtr
->buffer
= nil
;
269 nodePtr
->blockHeader
= nil
;
278 ////////////////////////////////// InsertTree ///////////////////////////////////
280 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
281 TreePathTable treePathTable
,
285 BlockDescriptor
*targetNode
,
288 Boolean replacingKey
,
291 InsertKey primaryKey
;
294 primaryKey
.keyPtr
= keyPtr
;
295 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
296 primaryKey
.recPtr
= recPtr
;
297 primaryKey
.recSize
= recSize
;
298 primaryKey
.replacingKey
= replacingKey
;
299 primaryKey
.skipRotate
= false;
301 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
302 targetNode
, index
, level
, insertNode
);
306 } // End of InsertTree
309 ////////////////////////////////// InsertLevel //////////////////////////////////
311 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
312 TreePathTable treePathTable
,
313 InsertKey
*primaryKey
,
314 InsertKey
*secondaryKey
,
315 BlockDescriptor
*targetNode
,
321 BlockDescriptor leftNode
;
322 UInt32 targetNodeNum
;
325 Boolean insertParent
;
326 Boolean updateParent
;
329 #if defined(applec) && !defined(__SC__)
330 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), "\P InsertLevel: non-leaf at level 1! ");
332 leftNode
.buffer
= nil
;
333 targetNodeNum
= treePathTable
[level
].node
;
335 insertParent
= false;
336 updateParent
= false;
338 ////// process first insert //////
340 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
341 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
346 // Extend the treePathTable by adding an entry for the new
347 // root node that references the current targetNode.
349 // If inserting the secondaryKey changes the first key of
350 // the target node, then we'll have to update the second
351 // key in the new root node.
353 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
354 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
358 *insertNode
= newNodeNum
;
360 ////// process second insert (if any) //////
362 if ( secondaryKey
!= nil
)
366 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
367 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
370 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
371 DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
374 //////////////////////// Update Parent(s) ///////////////////////////////
376 if ( insertParent
|| updateParent
)
378 BlockDescriptor parentNode
;
379 UInt32 parentNodeNum
;
386 PanicIf ( (level
== btreePtr
->treeDepth
), "\p InsertLevel: unfinished insert!?");
390 // Get Parent Node data...
391 index
= treePathTable
[level
].index
;
392 parentNodeNum
= treePathTable
[level
].node
;
394 PanicIf ( parentNodeNum
== 0, "\p InsertLevel: parent node is zero!?");
396 err
= GetNode (btreePtr
, parentNodeNum
, &parentNode
); // released as target node in next level up
398 #if defined(applec) && !defined(__SC__)
399 if (DEBUG_BUILD
&& level
> 1)
400 PanicIf ( ((NodeDescPtr
)parentNode
.buffer
)->kind
!= kBTIndexNode
, "\P InsertLevel: parent node not an index node! ");
402 ////////////////////////// Update Parent Index //////////////////////////////
406 //\80\80 debug: check if ptr == targetNodeNum
407 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
408 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p InsertLevel: parent ptr doesn't match target node!");
410 // need to delete and re-insert this parent key/ptr
411 // we delete it here and it gets re-inserted in the
412 // InsertLevel call below.
413 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
415 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
416 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
417 primaryKey
->recPtr
= (UInt8
*) &targetNodeNum
;
418 primaryKey
->recSize
= sizeof(targetNodeNum
);
419 primaryKey
->replacingKey
= kReplaceRecord
;
420 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
423 ////////////////////////// Add New Parent Index /////////////////////////////
427 InsertKey
*insertKeyPtr
;
432 insertKeyPtr
= &insertKey
;
433 secondaryKey
= &insertKey
;
437 insertKeyPtr
= primaryKey
;
440 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
441 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
442 insertKeyPtr
->recPtr
= (UInt8
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
443 insertKeyPtr
->recSize
= sizeof(UInt32
);
444 insertKeyPtr
->replacingKey
= kInsertRecord
;
445 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
448 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
449 &parentNode
, index
, level
, insertNode
);
453 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
456 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
463 (void) ReleaseNode (btreePtr
, targetNode
);
464 (void) ReleaseNode (btreePtr
, &leftNode
);
466 Panic ("\p InsertLevel: an error occured!");
470 } // End of InsertLevel
474 ////////////////////////////////// InsertNode ///////////////////////////////////
476 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
479 BlockDescriptor
*rightNode
,
486 BlockDescriptor
*leftNode
,
487 Boolean
*updateParent
,
488 Boolean
*insertParent
,
491 BlockDescriptor
*targetNode
;
499 PanicIf ( rightNode
->buffer
== leftNode
->buffer
, "\p InsertNode: rightNode == leftNode, huh?");
501 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
504 /////////////////////// Try Simple Insert ///////////////////////////////
506 if ( node
== leftNodeNum
)
507 targetNode
= leftNode
;
509 targetNode
= rightNode
;
511 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
518 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
519 *updateParent
= true; // the first record changed so we need to update the parent
523 //////////////////////// Try Rotate Left ////////////////////////////////
525 if ( !recordFit
&& leftNodeNum
> 0 )
527 PanicIf ( leftNode
->buffer
!= nil
, "\p InsertNode: leftNode already aquired!");
529 if ( leftNode
->buffer
== nil
)
531 err
= GetNode (btreePtr
, leftNodeNum
, leftNode
); // will be released by caller or a split below
535 PanicIf ( ((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
, "\p InsertNode, RotateLeft: invalid sibling link!" );
537 if ( !key
->skipRotate
) // are rotates allowed?
539 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
540 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
545 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
546 *updateParent
= true;
552 //////////////////////// Try Split Left /////////////////////////////////
556 // might not have left node...
557 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
558 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
561 // if we split root node - add new root
563 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
565 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
571 *insertParent
= true;
573 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
574 *updateParent
= true;
582 (void) ReleaseNode (btreePtr
, leftNode
);
585 } // End of InsertNode
588 /*-------------------------------------------------------------------------------
589 Routine: DeleteTree - One_line_description.
591 Function: Brief_description_of_the_function_and_any_side_effects
595 Input: btreePtr - description
596 treePathTable - description
597 targetNode - description
600 Result: noErr - success
602 -------------------------------------------------------------------------------*/
604 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
605 TreePathTable treePathTable
,
606 BlockDescriptor
*targetNode
,
611 BlockDescriptor parentNode
;
612 BTNodeDescriptor
*targetNodePtr
;
613 UInt32 targetNodeNum
;
614 Boolean deleteRequired
;
615 Boolean updateRequired
;
618 deleteRequired
= false;
619 updateRequired
= false;
621 targetNodeNum
= treePathTable
[level
].node
;
622 targetNodePtr
= targetNode
->buffer
;
623 PanicIf (targetNodePtr
== nil
, "\pDeleteTree: targetNode has nil buffer!");
625 DeleteRecord (btreePtr
, targetNodePtr
, index
);
627 //\80\80 coalesce remaining records?
629 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
631 BlockDescriptor siblingNode
;
632 UInt32 siblingNodeNum
;
634 deleteRequired
= true;
636 ////////////////// Get Siblings & Update Links //////////////////////////
638 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
639 if ( siblingNodeNum
!= 0 )
641 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
643 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
644 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
647 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
649 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
652 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
653 if ( siblingNodeNum
!= 0 )
655 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
657 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
658 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
661 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
663 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
666 //////////////////////// Free Empty Node ////////////////////////////////
668 ClearNode (btreePtr
, targetNodePtr
);
670 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
672 err
= FreeNode (btreePtr
, targetNodeNum
);
675 else if ( index
== 0 ) // did we delete the first record?
677 updateRequired
= true; // yes, so we need to update parent
681 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
683 deleteRequired
= false;
684 updateRequired
= false;
686 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
688 btreePtr
->rootNode
= 0;
689 btreePtr
->treeDepth
= 0;
691 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
693 err
= CollapseTree (btreePtr
, targetNode
);
699 if ( updateRequired
|| deleteRequired
)
701 ++level
; // next level
703 //// Get Parent Node and index
704 index
= treePathTable
[level
].index
;
705 err
= GetNode (btreePtr
, treePathTable
[level
].node
, &parentNode
);
708 if ( updateRequired
)
715 //\80\80 debug: check if ptr == targetNodeNum
716 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
717 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
719 // need to delete and re-insert this parent key/ptr
720 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
722 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
723 recPtr
= (UInt8
*) &targetNodeNum
;
724 recSize
= sizeof(targetNodeNum
);
726 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
727 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
730 else // deleteRequired
732 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
738 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
745 (void) ReleaseNode (btreePtr
, targetNode
);
746 (void) ReleaseNode (btreePtr
, &parentNode
);
754 ///////////////////////////////// CollapseTree //////////////////////////////////
756 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
757 BlockDescriptor
*blockPtr
)
763 originalRoot
= btreePtr
->rootNode
;
767 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
768 break; // this will make a fine root node
770 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
771 break; // we've hit bottom
773 nodeNum
= btreePtr
->rootNode
;
774 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
775 --btreePtr
->treeDepth
;
777 //// Clear and Free Current Old Root Node ////
778 ClearNode (btreePtr
, blockPtr
->buffer
);
779 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
781 err
= FreeNode (btreePtr
, nodeNum
);
784 //// Get New Root Node
785 err
= GetNode (btreePtr
, btreePtr
->rootNode
, blockPtr
);
789 if (btreePtr
->rootNode
!= originalRoot
)
790 M_BTreeHeaderDirty (btreePtr
);
792 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
798 /////////////////////////////////// ErrorExit ///////////////////////////////////
801 (void) ReleaseNode (btreePtr
, blockPtr
);
807 ////////////////////////////////// RotateLeft ///////////////////////////////////
809 /*-------------------------------------------------------------------------------
811 Routine: RotateLeft - One_line_description.
813 Function: Brief_description_of_the_function_and_any_side_effects
815 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
817 Input: btreePtr - description
818 leftNode - description
819 rightNode - description
820 rightInsertIndex - description
823 recSize - description
826 insertNodeNum - description
827 recordFit - description
830 Result: noErr - success
832 -------------------------------------------------------------------------------*/
834 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
835 NodeDescPtr leftNode
,
836 NodeDescPtr rightNode
,
837 UInt16 rightInsertIndex
,
842 UInt32
*insertNodeNum
,
844 UInt16
*recsRotated
)
849 SInt32 leftSize
, rightSize
;
852 UInt16 lengthFieldSize
;
853 UInt16 index
, moveIndex
;
856 ///////////////////// Determine If Record Will Fit //////////////////////////
858 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
860 // the key's length field is 8-bits in HFS and 16-bits in HFS+
861 if ( btreePtr
->attributes
& kBTBigKeysMask
)
862 lengthFieldSize
= sizeof(UInt16
);
864 lengthFieldSize
= sizeof(UInt8
);
866 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
868 if ( M_IsOdd (insertSize
) )
869 ++insertSize
; // add pad byte;
871 nodeSize
= btreePtr
->nodeSize
;
873 // add size of insert record to right node
874 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
875 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
879 while ( leftSize
< rightSize
)
881 if ( moveIndex
< rightInsertIndex
)
883 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
885 else if ( moveIndex
== rightInsertIndex
)
887 moveSize
= insertSize
;
889 else // ( moveIndex > rightInsertIndex )
891 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
894 leftSize
+= moveSize
;
895 rightSize
-= moveSize
;
899 if ( leftSize
> nodeSize
) // undo last move
901 leftSize
-= moveSize
;
902 rightSize
+= moveSize
;
906 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
916 // we've found balance point, moveIndex == number of records moved into leftNode
919 //////////////////////////// Rotate Records /////////////////////////////////
921 *recsRotated
= moveIndex
;
925 while ( index
< moveIndex
)
927 if ( index
== rightInsertIndex
) // insert new record in left node
929 UInt16 leftInsertIndex
;
931 leftInsertIndex
= leftNode
->numRecords
;
933 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
934 keyPtr
, keyLength
, recPtr
, recSize
);
937 Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
938 err
= fsBTBadRotateErr
;
942 *insertIndex
= leftInsertIndex
;
943 *insertNodeNum
= rightNode
->bLink
;
947 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
950 Panic ("\pRotateLeft: RotateRecordLeft returned false!");
951 err
= fsBTBadRotateErr
;
959 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
961 rightInsertIndex
-= index
; // adjust for records already rotated
963 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
964 keyPtr
, keyLength
, recPtr
, recSize
);
967 Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
968 err
= fsBTBadRotateErr
;
972 *insertIndex
= rightInsertIndex
;
973 *insertNodeNum
= leftNode
->fLink
;
980 ////////////////////////////// Error Exit ///////////////////////////////////
994 /////////////////////////////////// SplitLeft ///////////////////////////////////
996 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
997 BlockDescriptor
*leftNode
,
998 BlockDescriptor
*rightNode
,
1004 UInt16
*insertIndex
,
1005 UInt32
*insertNodeNum
,
1006 UInt16
*recsRotated
)
1009 NodeDescPtr left
, right
;
1014 ///////////////////////////// Compare Nodes /////////////////////////////////
1016 right
= rightNode
->buffer
;
1017 left
= leftNode
->buffer
;
1019 PanicIf ( right
->bLink
!= 0 && left
== 0, "\p SplitLeft: left sibling missing!?" );
1021 /* type should be kBTLeafNode or kBTIndexNode */
1023 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1024 return fsBTInvalidNodeErr
;
1028 if ( left
->fLink
!= rightNodeNum
)
1029 return fsBTInvalidNodeErr
; //\80\80 E_BadSibling ?
1031 if ( left
->height
!= right
->height
)
1032 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeHeight ?
1034 if ( left
->kind
!= right
->kind
)
1035 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeType ?
1039 ///////////////////////////// Allocate Node /////////////////////////////////
1041 err
= AllocateNode (btreePtr
, &newNodeNum
);
1042 M_ExitOnError (err
);
1045 /////////////// Update Forward Link In Original Left Node ///////////////////
1049 left
->fLink
= newNodeNum
;
1050 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1051 M_ExitOnError (err
);
1055 /////////////////////// Initialize New Left Node ////////////////////////////
1057 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1058 M_ExitOnError (err
);
1060 left
= leftNode
->buffer
;
1061 left
->fLink
= rightNodeNum
;
1064 // Steal Info From Right Node
1066 left
->bLink
= right
->bLink
;
1067 left
->kind
= right
->kind
;
1068 left
->height
= right
->height
;
1070 right
->bLink
= newNodeNum
; // update Right bLink
1072 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1074 // if we're adding a new first leaf node - update BTreeInfoRec
1076 btreePtr
->firstLeafNode
= newNodeNum
;
1077 M_BTreeHeaderDirty (btreePtr
); //\80\80 AllocateNode should have set the bit already...
1080 ////////////////////////////// Rotate Left //////////////////////////////////
1082 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1083 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1084 M_ExitOnError (err
);
1090 (void) ReleaseNode (btreePtr
, leftNode
);
1091 (void) ReleaseNode (btreePtr
, rightNode
);
1093 //\80\80 Free new node if allocated?
1104 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1106 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1107 NodeDescPtr leftNode
,
1108 NodeDescPtr rightNode
)
1114 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1115 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1117 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1122 DeleteRecord (btreePtr
, rightNode
, 0);
1128 //////////////////////////////// AddNewRootNode /////////////////////////////////
1130 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1131 NodeDescPtr leftNode
,
1132 NodeDescPtr rightNode
)
1135 BlockDescriptor rootNode
;
1141 PanicIf (leftNode
== nil
, "\pAddNewRootNode: leftNode == nil");
1142 PanicIf (rightNode
== nil
, "\pAddNewRootNode: rightNode == nil");
1145 /////////////////////// Initialize New Root Node ////////////////////////////
1147 err
= AllocateNode (btreePtr
, &rootNum
);
1148 M_ExitOnError (err
);
1150 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1151 M_ExitOnError (err
);
1153 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1154 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1157 ///////////////////// Insert Left Node Index Record /////////////////////////
1159 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1160 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1162 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1163 (UInt8
*) &rightNode
->bLink
, 4 );
1165 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1168 //////////////////// Insert Right Node Index Record /////////////////////////
1170 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1171 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1173 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1174 (UInt8
*) &leftNode
->fLink
, 4 );
1176 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1179 /////////////////////////// Release Root Node ///////////////////////////////
1181 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1182 M_ExitOnError (err
);
1184 // update BTreeInfoRec
1186 btreePtr
->rootNode
= rootNum
;
1187 btreePtr
->flags
|= kBTHeaderDirty
;
1192 ////////////////////////////// Error Exit ///////////////////////////////////
1200 static UInt16
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1204 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1205 length
= KeyLength (btreePtr
, key
); // just use actual key length
1207 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //\80\80 shouldn't we clear the pad bytes?