2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 Contains: Multi-node tree operations for the BTree Module.
30 Version: xxx put the technology version here xxx
32 Written by: Gordon Sheridan and Bill Bruffey
34 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
40 Other Contact: Mark Day
42 Technology: File Systems
50 Change History (most recent first):
52 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
53 <CS5> 12/8/97 djb Radar #2200632, CollapseTree wasn't marking root node dirty.
54 <CS4> 11/24/97 djb Radar #2005325, InsertLevel incorrectly handled root splits!
55 <CS3> 10/17/97 msd Conditionalize DebugStrs.
56 <CS2> 5/16/97 msd InsertNode() needs a return statement in ErrorExit.
57 <CS1> 4/23/97 djb first checked in
59 <HFS8> 3/17/97 DSH Conditionalize out Panic assertion for SC.
60 <HFS7> 3/3/97 djb Removed DebugStr in InsertLevel.
61 <HFS6> 2/19/97 djb Major re-write of insert code; added InsertLevel and InsertNode.
62 <HFS5> 1/27/97 djb InsertTree and DeleteTree are now recursive and support variable
64 <HFS4> 1/16/97 djb Removed DebugStr in SearchTree. Added initial support for
65 variable sized index keys.
66 <HFS3> 1/3/97 djb Changed len8 to length8.
67 <HFS2> 1/3/97 djb Added support for large keys.
68 <HFS1> 12/19/96 djb first checked in
70 History applicable to original Scarecrow Design:
72 <3> 10/25/96 ser Changing for new VFPI
73 <2> 1/22/96 dkh Add #include Memory.h
74 <1> 10/18/95 rst Moved from Scarecrow project.
76 <12> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
77 <11> 9/30/94 prp Get in sync with D2 interface changes.
78 <10> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
79 <9> 7/22/94 wjk Convert to the new set of header files.
80 <8> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
82 <7> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
83 agree with their prototypes.
84 <6> 5/21/93 gs Debug DeleteTree. Modify InsertTree for BTReplaceRecord.
85 <5> 5/10/93 gs Modify RotateLeft, and add DeleteTree, CollapseTree routines.
86 <4> 3/23/93 gs revise RotateLeft to use InsertKeyRecord instead of
88 <3> 3/23/93 gs Implement SplitLeft, InsertTree routine.
89 <2> 2/8/93 gs Implement SearchTree, and RotateLeft.
90 <1> 11/15/92 gs first checked in
94 #include "../headers/BTreesPrivate.h"
97 /////////////////////// Routines Internal To BTree Module ///////////////////////
102 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
104 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
105 NodeDescPtr leftNode
,
106 NodeDescPtr rightNode
);
108 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
109 BlockDescriptor
*blockPtr
);
111 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
112 NodeDescPtr leftNode
,
113 NodeDescPtr rightNode
,
114 UInt16 rightInsertIndex
,
119 UInt32
*insertNodeNum
,
121 UInt16
*recsRotated
);
123 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
124 NodeDescPtr leftNode
,
125 NodeDescPtr rightNode
);
127 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
128 BlockDescriptor
*leftNode
,
129 BlockDescriptor
*rightNode
,
136 UInt32
*insertNodeNum
,
137 UInt16
*recsRotated
);
141 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
142 TreePathTable treePathTable
,
143 InsertKey
*primaryKey
,
144 InsertKey
*secondaryKey
,
145 BlockDescriptor
*targetNode
,
148 UInt32
*insertNode
);
150 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
152 BlockDescriptor
*rightNode
,
157 BlockDescriptor
*leftNode
,
158 Boolean
*updateParent
,
159 Boolean
*insertParent
,
160 Boolean
*rootSplit
);
162 static UInt16
GetKeyLength (const BTreeControlBlock
*btreePtr
,
164 Boolean forLeafNode
);
168 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
171 /*-------------------------------------------------------------------------------
173 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
175 Function: Searches BTree for specified key, setting up the Tree Path Table to
176 reflect the search path.
179 Input: btreePtr - pointer to control block of BTree to search
180 keyPtr - pointer to the key to search for
181 treePathTable - pointer to the tree path table to construct
183 Output: nodeNum - number of the node containing the key position
184 iterator - BTreeIterator specifying record or insert position
186 Result: noErr - key found, index is record index
187 fsBTRecordNotFoundErr - key not found, index is insert index
188 fsBTEmptyErr - key not found, return params are nil
189 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
190 -------------------------------------------------------------------------------*/
192 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
193 BTreeKeyPtr searchKey
,
194 TreePathTable treePathTable
,
196 BlockDescriptor
*nodePtr
,
197 UInt16
*returnIndex
)
200 SInt16 level
; // Expected depth of current node
201 UInt32 curNodeNum
; // Current node we're searching
205 SInt8 nodeKind
; // Kind of current node (index/leaf)
211 curNodeNum
= btreePtr
->rootNode
;
212 level
= btreePtr
->treeDepth
;
214 if (level
== 0) // is the tree empty?
220 //\80\80 for debugging...
221 treePathTable
[0].node
= 0;
222 treePathTable
[0].index
= 0;
227 // [2550929] Node number 0 is the header node. It is never a valid
228 // index or leaf node. If we're ever asked to search through node 0,
229 // something has gone wrong (typically a bad child node number, or
230 // we found a node full of zeroes that we thought was an index node).
234 // Panic("\pSearchTree: curNodeNum is zero!");
239 err
= GetNode (btreePtr
, curNodeNum
, &nodeRec
);
246 // [2550929] Sanity check the node height and node type. We expect
247 // particular values at each iteration in the search. This checking
248 // quickly finds bad pointers, loops, and other damage to the
249 // hierarchy of the B-tree.
251 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
253 // Panic("\pIncorrect node height");
257 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
260 // Nodes at level 1 must be leaves, by definition
261 if (nodeKind
!= kBTLeafNode
)
263 // Panic("\pIncorrect node type: expected leaf");
270 // A node at any other depth must be an index node
271 if (nodeKind
!= kBTIndexNode
)
273 // Panic("\pIncorrect node type: expected index");
279 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
281 treePathTable
[level
].node
= curNodeNum
;
283 if (nodeKind
== kBTLeafNode
)
285 treePathTable
[level
].index
= index
;
286 break; // were done...
289 if ( (keyFound
!= true) && (index
!= 0))
292 treePathTable
[level
].index
= index
;
294 err
= GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
297 // [2550929] If we got an error, it is probably because the index was bad
298 // (typically a corrupt node that confused SearchNode). Invalidate the node
299 // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
300 // sources call this InvalidateNode.
302 (void) TrashNode(btreePtr
, &nodeRec
);
306 // Get the child pointer out of this index node. We're now done with the current
307 // node and can continue the search with the child node.
308 curNodeNum
= *(UInt32
*)dataPtr
;
309 err
= ReleaseNode (btreePtr
, &nodeRec
);
315 // The child node should be at a level one less than the parent.
319 *nodeNum
= curNodeNum
;
321 *returnIndex
= index
;
324 return noErr
; // searchKey found, index identifies record in node
326 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
329 (void) ReleaseNode(btreePtr
, &nodeRec
);
330 // fall into ErrorExit
335 nodePtr
->buffer
= nil
;
336 nodePtr
->blockHeader
= nil
;
345 ////////////////////////////////// InsertTree ///////////////////////////////////
347 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
348 TreePathTable treePathTable
,
352 BlockDescriptor
*targetNode
,
355 Boolean replacingKey
,
358 InsertKey primaryKey
;
361 primaryKey
.keyPtr
= keyPtr
;
362 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
363 primaryKey
.recPtr
= recPtr
;
364 primaryKey
.recSize
= recSize
;
365 primaryKey
.replacingKey
= replacingKey
;
366 primaryKey
.skipRotate
= false;
368 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
369 targetNode
, index
, level
, insertNode
);
373 } // End of InsertTree
376 ////////////////////////////////// InsertLevel //////////////////////////////////
378 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
379 TreePathTable treePathTable
,
380 InsertKey
*primaryKey
,
381 InsertKey
*secondaryKey
,
382 BlockDescriptor
*targetNode
,
388 BlockDescriptor leftNode
;
389 UInt32 targetNodeNum
;
392 Boolean insertParent
;
393 Boolean updateParent
;
397 #if defined(applec) && !defined(__SC__)
398 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), "\P InsertLevel: non-leaf at level 1! ");
400 leftNode
.buffer
= nil
;
401 leftNode
.blockHeader
= nil
;
402 targetNodeNum
= treePathTable
[level
].node
;
404 insertParent
= false;
405 updateParent
= false;
408 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
410 ////// process first insert //////
412 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
413 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
418 // Extend the treePathTable by adding an entry for the new
419 // root node that references the current targetNode.
421 // If inserting the secondaryKey changes the first key of
422 // the target node, then we'll have to update the second
423 // key in the new root node.
425 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
426 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
430 *insertNode
= newNodeNum
;
432 ////// process second insert (if any) //////
434 if ( secondaryKey
!= nil
)
438 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
439 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
442 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
443 DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
446 //////////////////////// Update Parent(s) ///////////////////////////////
448 if ( insertParent
|| updateParent
)
450 BlockDescriptor parentNode
;
451 UInt32 parentNodeNum
;
456 parentNode
.buffer
= nil
;
457 parentNode
.blockHeader
= nil
;
461 PanicIf ( (level
== btreePtr
->treeDepth
), "\p InsertLevel: unfinished insert!?");
465 // Get Parent Node data...
466 index
= treePathTable
[level
].index
;
467 parentNodeNum
= treePathTable
[level
].node
;
469 PanicIf ( parentNodeNum
== 0, "\p InsertLevel: parent node is zero!?");
471 err
= GetNode (btreePtr
, parentNodeNum
, &parentNode
); // released as target node in next level up
473 #if defined(applec) && !defined(__SC__)
474 if (DEBUG_BUILD
&& level
> 1)
475 PanicIf ( ((NodeDescPtr
)parentNode
.buffer
)->kind
!= kBTIndexNode
, "\P InsertLevel: parent node not an index node! ");
477 ////////////////////////// Update Parent Index //////////////////////////////
482 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
484 //\80\80 debug: check if ptr == targetNodeNum
485 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
486 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p InsertLevel: parent ptr doesn't match target node!");
488 // need to delete and re-insert this parent key/ptr
489 // we delete it here and it gets re-inserted in the
490 // InsertLevel call below.
491 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
493 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
494 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
495 primaryKey
->recPtr
= (UInt8
*) &targetNodeNum
;
496 primaryKey
->recSize
= sizeof(targetNodeNum
);
497 primaryKey
->replacingKey
= kReplaceRecord
;
498 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
501 ////////////////////////// Add New Parent Index /////////////////////////////
505 InsertKey
*insertKeyPtr
;
509 insertKeyPtr
= &insertKey
;
510 secondaryKey
= &insertKey
;
514 insertKeyPtr
= primaryKey
;
517 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
518 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
519 insertKeyPtr
->recPtr
= (UInt8
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
520 insertKeyPtr
->recSize
= sizeof(UInt32
);
521 insertKeyPtr
->replacingKey
= kInsertRecord
;
522 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
525 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
526 &parentNode
, index
, level
, insertNode
);
530 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
533 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
540 (void) ReleaseNode (btreePtr
, targetNode
);
541 (void) ReleaseNode (btreePtr
, &leftNode
);
543 Panic ("\p InsertLevel: an error occured!");
547 } // End of InsertLevel
551 ////////////////////////////////// InsertNode ///////////////////////////////////
553 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
556 BlockDescriptor
*rightNode
,
563 BlockDescriptor
*leftNode
,
564 Boolean
*updateParent
,
565 Boolean
*insertParent
,
568 BlockDescriptor
*targetNode
;
576 PanicIf ( rightNode
->buffer
== leftNode
->buffer
, "\p InsertNode: rightNode == leftNode, huh?");
578 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
581 /////////////////////// Try Simple Insert ///////////////////////////////
583 if ( node
== leftNodeNum
)
584 targetNode
= leftNode
;
586 targetNode
= rightNode
;
588 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
595 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
596 *updateParent
= true; // the first record changed so we need to update the parent
600 //////////////////////// Try Rotate Left ////////////////////////////////
602 if ( !recordFit
&& leftNodeNum
> 0 )
604 PanicIf ( leftNode
->buffer
!= nil
, "\p InsertNode: leftNode already aquired!");
606 if ( leftNode
->buffer
== nil
)
608 err
= GetNode (btreePtr
, leftNodeNum
, leftNode
); // will be released by caller or a split below
611 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
614 PanicIf ( ((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
, "\p InsertNode, RotateLeft: invalid sibling link!" );
616 if ( !key
->skipRotate
) // are rotates allowed?
618 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
619 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
624 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
625 *updateParent
= true;
631 //////////////////////// Try Split Left /////////////////////////////////
635 // might not have left node...
636 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
637 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
640 // if we split root node - add new root
642 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
644 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
650 *insertParent
= true;
652 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
653 *updateParent
= true;
660 (void) ReleaseNode (btreePtr
, leftNode
);
663 } // End of InsertNode
666 /*-------------------------------------------------------------------------------
667 Routine: DeleteTree - One_line_description.
669 Function: Brief_description_of_the_function_and_any_side_effects
673 Input: btreePtr - description
674 treePathTable - description
675 targetNode - description
678 Result: noErr - success
680 -------------------------------------------------------------------------------*/
682 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
683 TreePathTable treePathTable
,
684 BlockDescriptor
*targetNode
,
689 BlockDescriptor parentNode
;
690 BTNodeDescriptor
*targetNodePtr
;
691 UInt32 targetNodeNum
;
692 Boolean deleteRequired
;
693 Boolean updateRequired
;
695 // XXXdbg - initialize these to null in case we get an
696 // error and try to exit before it's initialized
697 parentNode
.buffer
= nil
;
698 parentNode
.blockHeader
= nil
;
700 deleteRequired
= false;
701 updateRequired
= false;
703 targetNodeNum
= treePathTable
[level
].node
;
704 targetNodePtr
= targetNode
->buffer
;
705 PanicIf (targetNodePtr
== nil
, "\pDeleteTree: targetNode has nil buffer!");
708 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
710 DeleteRecord (btreePtr
, targetNodePtr
, index
);
712 //\80\80 coalesce remaining records?
714 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
716 BlockDescriptor siblingNode
;
717 UInt32 siblingNodeNum
;
719 deleteRequired
= true;
721 siblingNode
.buffer
= nil
;
722 siblingNode
.blockHeader
= nil
;
724 ////////////////// Get Siblings & Update Links //////////////////////////
726 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
727 if ( siblingNodeNum
!= 0 )
729 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
733 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
735 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
736 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
739 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
741 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
744 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
745 if ( siblingNodeNum
!= 0 )
747 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
751 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
753 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
754 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
757 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
759 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
762 //////////////////////// Free Empty Node ////////////////////////////////
764 ClearNode (btreePtr
, targetNodePtr
);
766 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
769 err
= FreeNode (btreePtr
, targetNodeNum
);
772 else if ( index
== 0 ) // did we delete the first record?
774 updateRequired
= true; // yes, so we need to update parent
778 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
780 deleteRequired
= false;
781 updateRequired
= false;
783 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
785 btreePtr
->rootNode
= 0;
786 btreePtr
->treeDepth
= 0;
788 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
790 err
= CollapseTree (btreePtr
, targetNode
);
796 if ( updateRequired
|| deleteRequired
)
798 ++level
; // next level
800 //// Get Parent Node and index
801 index
= treePathTable
[level
].index
;
802 err
= GetNode (btreePtr
, treePathTable
[level
].node
, &parentNode
);
805 if ( updateRequired
)
813 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
815 //\80\80 debug: check if ptr == targetNodeNum
816 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
817 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
819 // need to delete and re-insert this parent key/ptr
820 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
822 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
823 recPtr
= (UInt8
*) &targetNodeNum
;
824 recSize
= sizeof(targetNodeNum
);
826 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
827 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
830 else // deleteRequired
832 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
838 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
845 (void) ReleaseNode (btreePtr
, targetNode
);
846 (void) ReleaseNode (btreePtr
, &parentNode
);
854 ///////////////////////////////// CollapseTree //////////////////////////////////
856 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
857 BlockDescriptor
*blockPtr
)
863 originalRoot
= btreePtr
->rootNode
;
866 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
870 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
871 break; // this will make a fine root node
873 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
874 break; // we've hit bottom
876 nodeNum
= btreePtr
->rootNode
;
877 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
878 --btreePtr
->treeDepth
;
880 //// Clear and Free Current Old Root Node ////
881 ClearNode (btreePtr
, blockPtr
->buffer
);
882 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
884 err
= FreeNode (btreePtr
, nodeNum
);
887 //// Get New Root Node
888 err
= GetNode (btreePtr
, btreePtr
->rootNode
, blockPtr
);
892 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
895 if (btreePtr
->rootNode
!= originalRoot
)
896 M_BTreeHeaderDirty (btreePtr
);
898 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
904 /////////////////////////////////// ErrorExit ///////////////////////////////////
907 (void) ReleaseNode (btreePtr
, blockPtr
);
913 ////////////////////////////////// RotateLeft ///////////////////////////////////
915 /*-------------------------------------------------------------------------------
917 Routine: RotateLeft - One_line_description.
919 Function: Brief_description_of_the_function_and_any_side_effects
921 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
923 Input: btreePtr - description
924 leftNode - description
925 rightNode - description
926 rightInsertIndex - description
929 recSize - description
932 insertNodeNum - description
933 recordFit - description
936 Result: noErr - success
938 -------------------------------------------------------------------------------*/
940 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
941 NodeDescPtr leftNode
,
942 NodeDescPtr rightNode
,
943 UInt16 rightInsertIndex
,
948 UInt32
*insertNodeNum
,
950 UInt16
*recsRotated
)
955 SInt32 leftSize
, rightSize
;
958 UInt16 lengthFieldSize
;
959 UInt16 index
, moveIndex
;
962 ///////////////////// Determine If Record Will Fit //////////////////////////
964 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
966 // the key's length field is 8-bits in HFS and 16-bits in HFS+
967 if ( btreePtr
->attributes
& kBTBigKeysMask
)
968 lengthFieldSize
= sizeof(UInt16
);
970 lengthFieldSize
= sizeof(UInt8
);
972 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
974 if ( M_IsOdd (insertSize
) )
975 ++insertSize
; // add pad byte;
977 nodeSize
= btreePtr
->nodeSize
;
979 // add size of insert record to right node
980 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
981 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
985 while ( leftSize
< rightSize
)
987 if ( moveIndex
< rightInsertIndex
)
989 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
991 else if ( moveIndex
== rightInsertIndex
)
993 moveSize
= insertSize
;
995 else // ( moveIndex > rightInsertIndex )
997 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
1000 leftSize
+= moveSize
;
1001 rightSize
-= moveSize
;
1005 if ( leftSize
> nodeSize
) // undo last move
1007 leftSize
-= moveSize
;
1008 rightSize
+= moveSize
;
1012 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
1022 // we've found balance point, moveIndex == number of records moved into leftNode
1025 //////////////////////////// Rotate Records /////////////////////////////////
1027 *recsRotated
= moveIndex
;
1031 while ( index
< moveIndex
)
1033 if ( index
== rightInsertIndex
) // insert new record in left node
1035 UInt16 leftInsertIndex
;
1037 leftInsertIndex
= leftNode
->numRecords
;
1039 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
1040 keyPtr
, keyLength
, recPtr
, recSize
);
1043 Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
1044 err
= fsBTBadRotateErr
;
1048 *insertIndex
= leftInsertIndex
;
1049 *insertNodeNum
= rightNode
->bLink
;
1053 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1056 Panic ("\pRotateLeft: RotateRecordLeft returned false!");
1057 err
= fsBTBadRotateErr
;
1065 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1067 rightInsertIndex
-= index
; // adjust for records already rotated
1069 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1070 keyPtr
, keyLength
, recPtr
, recSize
);
1073 Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
1074 err
= fsBTBadRotateErr
;
1078 *insertIndex
= rightInsertIndex
;
1079 *insertNodeNum
= leftNode
->fLink
;
1086 ////////////////////////////// Error Exit ///////////////////////////////////
1100 /////////////////////////////////// SplitLeft ///////////////////////////////////
1102 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1103 BlockDescriptor
*leftNode
,
1104 BlockDescriptor
*rightNode
,
1105 UInt32 rightNodeNum
,
1110 UInt16
*insertIndex
,
1111 UInt32
*insertNodeNum
,
1112 UInt16
*recsRotated
)
1115 NodeDescPtr left
, right
;
1120 ///////////////////////////// Compare Nodes /////////////////////////////////
1122 right
= rightNode
->buffer
;
1123 left
= leftNode
->buffer
;
1125 PanicIf ( right
->bLink
!= 0 && left
== 0, "\p SplitLeft: left sibling missing!?" );
1127 /* type should be kBTLeafNode or kBTIndexNode */
1129 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1130 return fsBTInvalidNodeErr
;
1134 if ( left
->fLink
!= rightNodeNum
)
1135 return fsBTInvalidNodeErr
; //\80\80 E_BadSibling ?
1137 if ( left
->height
!= right
->height
)
1138 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeHeight ?
1140 if ( left
->kind
!= right
->kind
)
1141 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeType ?
1145 ///////////////////////////// Allocate Node /////////////////////////////////
1147 err
= AllocateNode (btreePtr
, &newNodeNum
);
1148 M_ExitOnError (err
);
1151 /////////////// Update Forward Link In Original Left Node ///////////////////
1156 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1158 left
->fLink
= newNodeNum
;
1159 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1160 M_ExitOnError (err
);
1164 /////////////////////// Initialize New Left Node ////////////////////////////
1166 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1167 M_ExitOnError (err
);
1170 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1172 left
= leftNode
->buffer
;
1173 left
->fLink
= rightNodeNum
;
1176 // Steal Info From Right Node
1178 left
->bLink
= right
->bLink
;
1179 left
->kind
= right
->kind
;
1180 left
->height
= right
->height
;
1182 right
->bLink
= newNodeNum
; // update Right bLink
1184 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1186 // if we're adding a new first leaf node - update BTreeInfoRec
1188 btreePtr
->firstLeafNode
= newNodeNum
;
1189 M_BTreeHeaderDirty (btreePtr
); //\80\80 AllocateNode should have set the bit already...
1192 ////////////////////////////// Rotate Left //////////////////////////////////
1194 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1195 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1197 M_ExitOnError (err
);
1203 (void) ReleaseNode (btreePtr
, leftNode
);
1204 (void) ReleaseNode (btreePtr
, rightNode
);
1206 //\80\80 Free new node if allocated?
1217 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1219 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1220 NodeDescPtr leftNode
,
1221 NodeDescPtr rightNode
)
1227 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1228 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1230 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1235 DeleteRecord (btreePtr
, rightNode
, 0);
1241 //////////////////////////////// AddNewRootNode /////////////////////////////////
1243 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1244 NodeDescPtr leftNode
,
1245 NodeDescPtr rightNode
)
1248 BlockDescriptor rootNode
;
1254 rootNode
.buffer
= nil
;
1255 rootNode
.blockHeader
= nil
;
1257 PanicIf (leftNode
== nil
, "\pAddNewRootNode: leftNode == nil");
1258 PanicIf (rightNode
== nil
, "\pAddNewRootNode: rightNode == nil");
1261 /////////////////////// Initialize New Root Node ////////////////////////////
1263 err
= AllocateNode (btreePtr
, &rootNum
);
1264 M_ExitOnError (err
);
1266 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1267 M_ExitOnError (err
);
1270 ModifyBlockStart(btreePtr
->fileRefNum
, &rootNode
);
1272 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1273 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1276 ///////////////////// Insert Left Node Index Record /////////////////////////
1278 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1279 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1281 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1282 (UInt8
*) &rightNode
->bLink
, 4 );
1284 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1287 //////////////////// Insert Right Node Index Record /////////////////////////
1289 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1290 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1292 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1293 (UInt8
*) &leftNode
->fLink
, 4 );
1295 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1298 /////////////////////////// Release Root Node ///////////////////////////////
1300 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1301 M_ExitOnError (err
);
1303 // update BTreeInfoRec
1305 btreePtr
->rootNode
= rootNum
;
1306 btreePtr
->flags
|= kBTHeaderDirty
;
1311 ////////////////////////////// Error Exit ///////////////////////////////////
1319 static UInt16
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1323 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1324 length
= KeyLength (btreePtr
, key
); // just use actual key length
1326 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //\80\80 shouldn't we clear the pad bytes?