2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 Contains: Multi-node tree operations for the BTree Module.
33 Version: xxx put the technology version here xxx
35 Written by: Gordon Sheridan and Bill Bruffey
37 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
43 Other Contact: Mark Day
45 Technology: File Systems
53 Change History (most recent first):
55 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
56 <CS5> 12/8/97 djb Radar #2200632, CollapseTree wasn't marking root node dirty.
57 <CS4> 11/24/97 djb Radar #2005325, InsertLevel incorrectly handled root splits!
58 <CS3> 10/17/97 msd Conditionalize DebugStrs.
59 <CS2> 5/16/97 msd InsertNode() needs a return statement in ErrorExit.
60 <CS1> 4/23/97 djb first checked in
62 <HFS8> 3/17/97 DSH Conditionalize out Panic assertion for SC.
63 <HFS7> 3/3/97 djb Removed DebugStr in InsertLevel.
64 <HFS6> 2/19/97 djb Major re-write of insert code; added InsertLevel and InsertNode.
65 <HFS5> 1/27/97 djb InsertTree and DeleteTree are now recursive and support variable
67 <HFS4> 1/16/97 djb Removed DebugStr in SearchTree. Added initial support for
68 variable sized index keys.
69 <HFS3> 1/3/97 djb Changed len8 to length8.
70 <HFS2> 1/3/97 djb Added support for large keys.
71 <HFS1> 12/19/96 djb first checked in
73 History applicable to original Scarecrow Design:
75 <3> 10/25/96 ser Changing for new VFPI
76 <2> 1/22/96 dkh Add #include Memory.h
77 <1> 10/18/95 rst Moved from Scarecrow project.
79 <12> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
80 <11> 9/30/94 prp Get in sync with D2 interface changes.
81 <10> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
82 <9> 7/22/94 wjk Convert to the new set of header files.
83 <8> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
85 <7> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
86 agree with their prototypes.
87 <6> 5/21/93 gs Debug DeleteTree. Modify InsertTree for BTReplaceRecord.
88 <5> 5/10/93 gs Modify RotateLeft, and add DeleteTree, CollapseTree routines.
89 <4> 3/23/93 gs revise RotateLeft to use InsertKeyRecord instead of
91 <3> 3/23/93 gs Implement SplitLeft, InsertTree routine.
92 <2> 2/8/93 gs Implement SearchTree, and RotateLeft.
93 <1> 11/15/92 gs first checked in
97 #include "../headers/BTreesPrivate.h"
100 /////////////////////// Routines Internal To BTree Module ///////////////////////
105 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
107 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
108 NodeDescPtr leftNode
,
109 NodeDescPtr rightNode
);
111 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
112 BlockDescriptor
*blockPtr
);
114 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
115 NodeDescPtr leftNode
,
116 NodeDescPtr rightNode
,
117 UInt16 rightInsertIndex
,
122 UInt32
*insertNodeNum
,
124 UInt16
*recsRotated
);
126 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
127 NodeDescPtr leftNode
,
128 NodeDescPtr rightNode
);
130 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
131 BlockDescriptor
*leftNode
,
132 BlockDescriptor
*rightNode
,
139 UInt32
*insertNodeNum
,
140 UInt16
*recsRotated
);
144 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
145 TreePathTable treePathTable
,
146 InsertKey
*primaryKey
,
147 InsertKey
*secondaryKey
,
148 BlockDescriptor
*targetNode
,
151 UInt32
*insertNode
);
153 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
155 BlockDescriptor
*rightNode
,
160 BlockDescriptor
*leftNode
,
161 Boolean
*updateParent
,
162 Boolean
*insertParent
,
163 Boolean
*rootSplit
);
165 static UInt16
GetKeyLength (const BTreeControlBlock
*btreePtr
,
167 Boolean forLeafNode
);
171 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
174 /*-------------------------------------------------------------------------------
176 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
178 Function: Searches BTree for specified key, setting up the Tree Path Table to
179 reflect the search path.
182 Input: btreePtr - pointer to control block of BTree to search
183 keyPtr - pointer to the key to search for
184 treePathTable - pointer to the tree path table to construct
186 Output: nodeNum - number of the node containing the key position
187 iterator - BTreeIterator specifying record or insert position
189 Result: noErr - key found, index is record index
190 fsBTRecordNotFoundErr - key not found, index is insert index
191 fsBTEmptyErr - key not found, return params are nil
192 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
193 -------------------------------------------------------------------------------*/
195 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
196 BTreeKeyPtr searchKey
,
197 TreePathTable treePathTable
,
199 BlockDescriptor
*nodePtr
,
200 UInt16
*returnIndex
)
203 SInt16 level
; // Expected depth of current node
204 UInt32 curNodeNum
; // Current node we're searching
208 SInt8 nodeKind
; // Kind of current node (index/leaf)
214 curNodeNum
= btreePtr
->rootNode
;
215 level
= btreePtr
->treeDepth
;
217 if (level
== 0) // is the tree empty?
223 //\80\80 for debugging...
224 treePathTable
[0].node
= 0;
225 treePathTable
[0].index
= 0;
230 // [2550929] Node number 0 is the header node. It is never a valid
231 // index or leaf node. If we're ever asked to search through node 0,
232 // something has gone wrong (typically a bad child node number, or
233 // we found a node full of zeroes that we thought was an index node).
237 // Panic("\pSearchTree: curNodeNum is zero!");
242 err
= GetNode (btreePtr
, curNodeNum
, &nodeRec
);
249 // [2550929] Sanity check the node height and node type. We expect
250 // particular values at each iteration in the search. This checking
251 // quickly finds bad pointers, loops, and other damage to the
252 // hierarchy of the B-tree.
254 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
256 // Panic("\pIncorrect node height");
260 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
263 // Nodes at level 1 must be leaves, by definition
264 if (nodeKind
!= kBTLeafNode
)
266 // Panic("\pIncorrect node type: expected leaf");
273 // A node at any other depth must be an index node
274 if (nodeKind
!= kBTIndexNode
)
276 // Panic("\pIncorrect node type: expected index");
282 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
284 treePathTable
[level
].node
= curNodeNum
;
286 if (nodeKind
== kBTLeafNode
)
288 treePathTable
[level
].index
= index
;
289 break; // were done...
292 if ( (keyFound
!= true) && (index
!= 0))
295 treePathTable
[level
].index
= index
;
297 err
= GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
300 // [2550929] If we got an error, it is probably because the index was bad
301 // (typically a corrupt node that confused SearchNode). Invalidate the node
302 // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
303 // sources call this InvalidateNode.
305 (void) TrashNode(btreePtr
, &nodeRec
);
309 // Get the child pointer out of this index node. We're now done with the current
310 // node and can continue the search with the child node.
311 curNodeNum
= *(UInt32
*)dataPtr
;
312 err
= ReleaseNode (btreePtr
, &nodeRec
);
318 // The child node should be at a level one less than the parent.
322 *nodeNum
= curNodeNum
;
324 *returnIndex
= index
;
327 return noErr
; // searchKey found, index identifies record in node
329 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
332 (void) ReleaseNode(btreePtr
, &nodeRec
);
333 // fall into ErrorExit
338 nodePtr
->buffer
= nil
;
339 nodePtr
->blockHeader
= nil
;
348 ////////////////////////////////// InsertTree ///////////////////////////////////
350 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
351 TreePathTable treePathTable
,
355 BlockDescriptor
*targetNode
,
358 Boolean replacingKey
,
361 InsertKey primaryKey
;
364 primaryKey
.keyPtr
= keyPtr
;
365 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
366 primaryKey
.recPtr
= recPtr
;
367 primaryKey
.recSize
= recSize
;
368 primaryKey
.replacingKey
= replacingKey
;
369 primaryKey
.skipRotate
= false;
371 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
372 targetNode
, index
, level
, insertNode
);
376 } // End of InsertTree
379 ////////////////////////////////// InsertLevel //////////////////////////////////
381 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
382 TreePathTable treePathTable
,
383 InsertKey
*primaryKey
,
384 InsertKey
*secondaryKey
,
385 BlockDescriptor
*targetNode
,
391 BlockDescriptor leftNode
;
392 UInt32 targetNodeNum
;
395 Boolean insertParent
;
396 Boolean updateParent
;
400 #if defined(applec) && !defined(__SC__)
401 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), "\P InsertLevel: non-leaf at level 1! ");
403 leftNode
.buffer
= nil
;
404 leftNode
.blockHeader
= nil
;
405 targetNodeNum
= treePathTable
[level
].node
;
407 insertParent
= false;
408 updateParent
= false;
411 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
413 ////// process first insert //////
415 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
416 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
421 // Extend the treePathTable by adding an entry for the new
422 // root node that references the current targetNode.
424 // If inserting the secondaryKey changes the first key of
425 // the target node, then we'll have to update the second
426 // key in the new root node.
428 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
429 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
433 *insertNode
= newNodeNum
;
435 ////// process second insert (if any) //////
437 if ( secondaryKey
!= nil
)
441 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
442 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
445 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
446 DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
449 //////////////////////// Update Parent(s) ///////////////////////////////
451 if ( insertParent
|| updateParent
)
453 BlockDescriptor parentNode
;
454 UInt32 parentNodeNum
;
459 parentNode
.buffer
= nil
;
460 parentNode
.blockHeader
= nil
;
464 PanicIf ( (level
== btreePtr
->treeDepth
), "\p InsertLevel: unfinished insert!?");
468 // Get Parent Node data...
469 index
= treePathTable
[level
].index
;
470 parentNodeNum
= treePathTable
[level
].node
;
472 PanicIf ( parentNodeNum
== 0, "\p InsertLevel: parent node is zero!?");
474 err
= GetNode (btreePtr
, parentNodeNum
, &parentNode
); // released as target node in next level up
476 #if defined(applec) && !defined(__SC__)
477 if (DEBUG_BUILD
&& level
> 1)
478 PanicIf ( ((NodeDescPtr
)parentNode
.buffer
)->kind
!= kBTIndexNode
, "\P InsertLevel: parent node not an index node! ");
480 ////////////////////////// Update Parent Index //////////////////////////////
485 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
487 //\80\80 debug: check if ptr == targetNodeNum
488 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
489 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p InsertLevel: parent ptr doesn't match target node!");
491 // need to delete and re-insert this parent key/ptr
492 // we delete it here and it gets re-inserted in the
493 // InsertLevel call below.
494 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
496 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
497 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
498 primaryKey
->recPtr
= (UInt8
*) &targetNodeNum
;
499 primaryKey
->recSize
= sizeof(targetNodeNum
);
500 primaryKey
->replacingKey
= kReplaceRecord
;
501 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
504 ////////////////////////// Add New Parent Index /////////////////////////////
508 InsertKey
*insertKeyPtr
;
512 insertKeyPtr
= &insertKey
;
513 secondaryKey
= &insertKey
;
517 insertKeyPtr
= primaryKey
;
520 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
521 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
522 insertKeyPtr
->recPtr
= (UInt8
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
523 insertKeyPtr
->recSize
= sizeof(UInt32
);
524 insertKeyPtr
->replacingKey
= kInsertRecord
;
525 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
528 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
529 &parentNode
, index
, level
, insertNode
);
533 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
536 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
543 (void) ReleaseNode (btreePtr
, targetNode
);
544 (void) ReleaseNode (btreePtr
, &leftNode
);
546 Panic ("\p InsertLevel: an error occurred!");
550 } // End of InsertLevel
554 ////////////////////////////////// InsertNode ///////////////////////////////////
556 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
559 BlockDescriptor
*rightNode
,
566 BlockDescriptor
*leftNode
,
567 Boolean
*updateParent
,
568 Boolean
*insertParent
,
571 BlockDescriptor
*targetNode
;
579 PanicIf ( rightNode
->buffer
== leftNode
->buffer
, "\p InsertNode: rightNode == leftNode, huh?");
581 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
584 /////////////////////// Try Simple Insert ///////////////////////////////
586 if ( node
== leftNodeNum
)
587 targetNode
= leftNode
;
589 targetNode
= rightNode
;
591 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
598 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
599 *updateParent
= true; // the first record changed so we need to update the parent
603 //////////////////////// Try Rotate Left ////////////////////////////////
605 if ( !recordFit
&& leftNodeNum
> 0 )
607 PanicIf ( leftNode
->buffer
!= nil
, "\p InsertNode: leftNode already aquired!");
609 if ( leftNode
->buffer
== nil
)
611 err
= GetNode (btreePtr
, leftNodeNum
, leftNode
); // will be released by caller or a split below
614 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
617 PanicIf ( ((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
, "\p InsertNode, RotateLeft: invalid sibling link!" );
619 if ( !key
->skipRotate
) // are rotates allowed?
621 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
622 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
627 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
628 *updateParent
= true;
634 //////////////////////// Try Split Left /////////////////////////////////
638 // might not have left node...
639 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
640 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
643 // if we split root node - add new root
645 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
647 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
653 *insertParent
= true;
655 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
656 *updateParent
= true;
663 (void) ReleaseNode (btreePtr
, leftNode
);
666 } // End of InsertNode
669 /*-------------------------------------------------------------------------------
670 Routine: DeleteTree - One_line_description.
672 Function: Brief_description_of_the_function_and_any_side_effects
676 Input: btreePtr - description
677 treePathTable - description
678 targetNode - description
681 Result: noErr - success
683 -------------------------------------------------------------------------------*/
685 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
686 TreePathTable treePathTable
,
687 BlockDescriptor
*targetNode
,
692 BlockDescriptor parentNode
;
693 BTNodeDescriptor
*targetNodePtr
;
694 UInt32 targetNodeNum
;
695 Boolean deleteRequired
;
696 Boolean updateRequired
;
698 // XXXdbg - initialize these to null in case we get an
699 // error and try to exit before it's initialized
700 parentNode
.buffer
= nil
;
701 parentNode
.blockHeader
= nil
;
703 deleteRequired
= false;
704 updateRequired
= false;
706 targetNodeNum
= treePathTable
[level
].node
;
707 targetNodePtr
= targetNode
->buffer
;
708 PanicIf (targetNodePtr
== nil
, "\pDeleteTree: targetNode has nil buffer!");
711 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
713 DeleteRecord (btreePtr
, targetNodePtr
, index
);
715 //\80\80 coalesce remaining records?
717 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
719 BlockDescriptor siblingNode
;
720 UInt32 siblingNodeNum
;
722 deleteRequired
= true;
724 siblingNode
.buffer
= nil
;
725 siblingNode
.blockHeader
= nil
;
727 ////////////////// Get Siblings & Update Links //////////////////////////
729 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
730 if ( siblingNodeNum
!= 0 )
732 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
736 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
738 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
739 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
742 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
744 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
747 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
748 if ( siblingNodeNum
!= 0 )
750 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
754 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
756 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
757 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
760 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
762 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
765 //////////////////////// Free Empty Node ////////////////////////////////
767 ClearNode (btreePtr
, targetNodePtr
);
769 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
772 err
= FreeNode (btreePtr
, targetNodeNum
);
775 else if ( index
== 0 ) // did we delete the first record?
777 updateRequired
= true; // yes, so we need to update parent
781 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
783 deleteRequired
= false;
784 updateRequired
= false;
786 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
788 btreePtr
->rootNode
= 0;
789 btreePtr
->treeDepth
= 0;
791 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
793 err
= CollapseTree (btreePtr
, targetNode
);
799 if ( updateRequired
|| deleteRequired
)
801 ++level
; // next level
803 //// Get Parent Node and index
804 index
= treePathTable
[level
].index
;
805 err
= GetNode (btreePtr
, treePathTable
[level
].node
, &parentNode
);
808 if ( updateRequired
)
816 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
818 //\80\80 debug: check if ptr == targetNodeNum
819 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
820 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
822 // need to delete and re-insert this parent key/ptr
823 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
825 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
826 recPtr
= (UInt8
*) &targetNodeNum
;
827 recSize
= sizeof(targetNodeNum
);
829 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
830 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
833 else // deleteRequired
835 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
841 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
848 (void) ReleaseNode (btreePtr
, targetNode
);
849 (void) ReleaseNode (btreePtr
, &parentNode
);
857 ///////////////////////////////// CollapseTree //////////////////////////////////
859 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
860 BlockDescriptor
*blockPtr
)
866 originalRoot
= btreePtr
->rootNode
;
869 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
873 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
874 break; // this will make a fine root node
876 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
877 break; // we've hit bottom
879 nodeNum
= btreePtr
->rootNode
;
880 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
881 --btreePtr
->treeDepth
;
883 //// Clear and Free Current Old Root Node ////
884 ClearNode (btreePtr
, blockPtr
->buffer
);
885 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
887 err
= FreeNode (btreePtr
, nodeNum
);
890 //// Get New Root Node
891 err
= GetNode (btreePtr
, btreePtr
->rootNode
, blockPtr
);
895 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
898 if (btreePtr
->rootNode
!= originalRoot
)
899 M_BTreeHeaderDirty (btreePtr
);
901 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
907 /////////////////////////////////// ErrorExit ///////////////////////////////////
910 (void) ReleaseNode (btreePtr
, blockPtr
);
916 ////////////////////////////////// RotateLeft ///////////////////////////////////
918 /*-------------------------------------------------------------------------------
920 Routine: RotateLeft - One_line_description.
922 Function: Brief_description_of_the_function_and_any_side_effects
924 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
926 Input: btreePtr - description
927 leftNode - description
928 rightNode - description
929 rightInsertIndex - description
932 recSize - description
935 insertNodeNum - description
936 recordFit - description
939 Result: noErr - success
941 -------------------------------------------------------------------------------*/
943 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
944 NodeDescPtr leftNode
,
945 NodeDescPtr rightNode
,
946 UInt16 rightInsertIndex
,
951 UInt32
*insertNodeNum
,
953 UInt16
*recsRotated
)
958 SInt32 leftSize
, rightSize
;
961 UInt16 lengthFieldSize
;
962 UInt16 index
, moveIndex
;
965 ///////////////////// Determine If Record Will Fit //////////////////////////
967 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
969 // the key's length field is 8-bits in HFS and 16-bits in HFS+
970 if ( btreePtr
->attributes
& kBTBigKeysMask
)
971 lengthFieldSize
= sizeof(UInt16
);
973 lengthFieldSize
= sizeof(UInt8
);
975 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
977 if ( M_IsOdd (insertSize
) )
978 ++insertSize
; // add pad byte;
980 nodeSize
= btreePtr
->nodeSize
;
982 // add size of insert record to right node
983 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
984 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
988 while ( leftSize
< rightSize
)
990 if ( moveIndex
< rightInsertIndex
)
992 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
994 else if ( moveIndex
== rightInsertIndex
)
996 moveSize
= insertSize
;
998 else // ( moveIndex > rightInsertIndex )
1000 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
1003 leftSize
+= moveSize
;
1004 rightSize
-= moveSize
;
1008 if ( leftSize
> nodeSize
) // undo last move
1010 leftSize
-= moveSize
;
1011 rightSize
+= moveSize
;
1015 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
1025 // we've found balance point, moveIndex == number of records moved into leftNode
1028 //////////////////////////// Rotate Records /////////////////////////////////
1030 *recsRotated
= moveIndex
;
1034 while ( index
< moveIndex
)
1036 if ( index
== rightInsertIndex
) // insert new record in left node
1038 UInt16 leftInsertIndex
;
1040 leftInsertIndex
= leftNode
->numRecords
;
1042 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
1043 keyPtr
, keyLength
, recPtr
, recSize
);
1046 Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
1047 err
= fsBTBadRotateErr
;
1051 *insertIndex
= leftInsertIndex
;
1052 *insertNodeNum
= rightNode
->bLink
;
1056 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1059 Panic ("\pRotateLeft: RotateRecordLeft returned false!");
1060 err
= fsBTBadRotateErr
;
1068 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1070 rightInsertIndex
-= index
; // adjust for records already rotated
1072 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1073 keyPtr
, keyLength
, recPtr
, recSize
);
1076 Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
1077 err
= fsBTBadRotateErr
;
1081 *insertIndex
= rightInsertIndex
;
1082 *insertNodeNum
= leftNode
->fLink
;
1089 ////////////////////////////// Error Exit ///////////////////////////////////
1103 /////////////////////////////////// SplitLeft ///////////////////////////////////
1105 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1106 BlockDescriptor
*leftNode
,
1107 BlockDescriptor
*rightNode
,
1108 UInt32 rightNodeNum
,
1113 UInt16
*insertIndex
,
1114 UInt32
*insertNodeNum
,
1115 UInt16
*recsRotated
)
1118 NodeDescPtr left
, right
;
1123 ///////////////////////////// Compare Nodes /////////////////////////////////
1125 right
= rightNode
->buffer
;
1126 left
= leftNode
->buffer
;
1128 PanicIf ( right
->bLink
!= 0 && left
== 0, "\p SplitLeft: left sibling missing!?" );
1130 /* type should be kBTLeafNode or kBTIndexNode */
1132 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1133 return fsBTInvalidNodeErr
;
1137 if ( left
->fLink
!= rightNodeNum
)
1138 return fsBTInvalidNodeErr
; //\80\80 E_BadSibling ?
1140 if ( left
->height
!= right
->height
)
1141 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeHeight ?
1143 if ( left
->kind
!= right
->kind
)
1144 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeType ?
1148 ///////////////////////////// Allocate Node /////////////////////////////////
1150 err
= AllocateNode (btreePtr
, &newNodeNum
);
1151 M_ExitOnError (err
);
1154 /////////////// Update Forward Link In Original Left Node ///////////////////
1159 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1161 left
->fLink
= newNodeNum
;
1162 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1163 M_ExitOnError (err
);
1167 /////////////////////// Initialize New Left Node ////////////////////////////
1169 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1170 M_ExitOnError (err
);
1173 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1175 left
= leftNode
->buffer
;
1176 left
->fLink
= rightNodeNum
;
1179 // Steal Info From Right Node
1181 left
->bLink
= right
->bLink
;
1182 left
->kind
= right
->kind
;
1183 left
->height
= right
->height
;
1185 right
->bLink
= newNodeNum
; // update Right bLink
1187 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1189 // if we're adding a new first leaf node - update BTreeInfoRec
1191 btreePtr
->firstLeafNode
= newNodeNum
;
1192 M_BTreeHeaderDirty (btreePtr
); //\80\80 AllocateNode should have set the bit already...
1195 ////////////////////////////// Rotate Left //////////////////////////////////
1197 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1198 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1200 M_ExitOnError (err
);
1206 (void) ReleaseNode (btreePtr
, leftNode
);
1207 (void) ReleaseNode (btreePtr
, rightNode
);
1209 //\80\80 Free new node if allocated?
1220 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1222 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1223 NodeDescPtr leftNode
,
1224 NodeDescPtr rightNode
)
1230 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1231 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1233 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1238 DeleteRecord (btreePtr
, rightNode
, 0);
1244 //////////////////////////////// AddNewRootNode /////////////////////////////////
1246 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1247 NodeDescPtr leftNode
,
1248 NodeDescPtr rightNode
)
1251 BlockDescriptor rootNode
;
1257 rootNode
.buffer
= nil
;
1258 rootNode
.blockHeader
= nil
;
1260 PanicIf (leftNode
== nil
, "\pAddNewRootNode: leftNode == nil");
1261 PanicIf (rightNode
== nil
, "\pAddNewRootNode: rightNode == nil");
1264 /////////////////////// Initialize New Root Node ////////////////////////////
1266 err
= AllocateNode (btreePtr
, &rootNum
);
1267 M_ExitOnError (err
);
1269 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1270 M_ExitOnError (err
);
1273 ModifyBlockStart(btreePtr
->fileRefNum
, &rootNode
);
1275 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1276 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1279 ///////////////////// Insert Left Node Index Record /////////////////////////
1281 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1282 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1284 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1285 (UInt8
*) &rightNode
->bLink
, 4 );
1287 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1290 //////////////////// Insert Right Node Index Record /////////////////////////
1292 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1293 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1295 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1296 (UInt8
*) &leftNode
->fLink
, 4 );
1298 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1301 /////////////////////////// Release Root Node ///////////////////////////////
1303 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1304 M_ExitOnError (err
);
1306 // update BTreeInfoRec
1308 btreePtr
->rootNode
= rootNum
;
1309 btreePtr
->flags
|= kBTHeaderDirty
;
1314 ////////////////////////////// Error Exit ///////////////////////////////////
1322 static UInt16
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1326 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1327 length
= KeyLength (btreePtr
, key
); // just use actual key length
1329 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //\80\80 shouldn't we clear the pad bytes?