2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
33 Contains: Multi-node tree operations for the BTree Module.
35 Version: xxx put the technology version here xxx
37 Written by: Gordon Sheridan and Bill Bruffey
39 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
45 Other Contact: Mark Day
47 Technology: File Systems
55 Change History (most recent first):
57 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
58 <CS5> 12/8/97 djb Radar #2200632, CollapseTree wasn't marking root node dirty.
59 <CS4> 11/24/97 djb Radar #2005325, InsertLevel incorrectly handled root splits!
60 <CS3> 10/17/97 msd Conditionalize DebugStrs.
61 <CS2> 5/16/97 msd InsertNode() needs a return statement in ErrorExit.
62 <CS1> 4/23/97 djb first checked in
64 <HFS8> 3/17/97 DSH Conditionalize out Panic assertion for SC.
65 <HFS7> 3/3/97 djb Removed DebugStr in InsertLevel.
66 <HFS6> 2/19/97 djb Major re-write of insert code; added InsertLevel and InsertNode.
67 <HFS5> 1/27/97 djb InsertTree and DeleteTree are now recursive and support variable
69 <HFS4> 1/16/97 djb Removed DebugStr in SearchTree. Added initial support for
70 variable sized index keys.
71 <HFS3> 1/3/97 djb Changed len8 to length8.
72 <HFS2> 1/3/97 djb Added support for large keys.
73 <HFS1> 12/19/96 djb first checked in
75 History applicable to original Scarecrow Design:
77 <3> 10/25/96 ser Changing for new VFPI
78 <2> 1/22/96 dkh Add #include Memory.h
79 <1> 10/18/95 rst Moved from Scarecrow project.
81 <12> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
82 <11> 9/30/94 prp Get in sync with D2 interface changes.
83 <10> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
84 <9> 7/22/94 wjk Convert to the new set of header files.
85 <8> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
87 <7> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
88 agree with their prototypes.
89 <6> 5/21/93 gs Debug DeleteTree. Modify InsertTree for BTReplaceRecord.
90 <5> 5/10/93 gs Modify RotateLeft, and add DeleteTree, CollapseTree routines.
91 <4> 3/23/93 gs revise RotateLeft to use InsertKeyRecord instead of
93 <3> 3/23/93 gs Implement SplitLeft, InsertTree routine.
94 <2> 2/8/93 gs Implement SearchTree, and RotateLeft.
95 <1> 11/15/92 gs first checked in
99 #include "../headers/BTreesPrivate.h"
102 /////////////////////// Routines Internal To BTree Module ///////////////////////
107 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
109 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
110 NodeDescPtr leftNode
,
111 NodeDescPtr rightNode
);
113 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
114 BlockDescriptor
*blockPtr
);
116 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
117 NodeDescPtr leftNode
,
118 NodeDescPtr rightNode
,
119 UInt16 rightInsertIndex
,
124 UInt32
*insertNodeNum
,
126 UInt16
*recsRotated
);
128 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
129 NodeDescPtr leftNode
,
130 NodeDescPtr rightNode
);
132 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
133 BlockDescriptor
*leftNode
,
134 BlockDescriptor
*rightNode
,
141 UInt32
*insertNodeNum
,
142 UInt16
*recsRotated
);
146 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
147 TreePathTable treePathTable
,
148 InsertKey
*primaryKey
,
149 InsertKey
*secondaryKey
,
150 BlockDescriptor
*targetNode
,
153 UInt32
*insertNode
);
155 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
157 BlockDescriptor
*rightNode
,
162 BlockDescriptor
*leftNode
,
163 Boolean
*updateParent
,
164 Boolean
*insertParent
,
165 Boolean
*rootSplit
);
167 static UInt16
GetKeyLength (const BTreeControlBlock
*btreePtr
,
169 Boolean forLeafNode
);
173 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
176 /*-------------------------------------------------------------------------------
178 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
180 Function: Searches BTree for specified key, setting up the Tree Path Table to
181 reflect the search path.
184 Input: btreePtr - pointer to control block of BTree to search
185 keyPtr - pointer to the key to search for
186 treePathTable - pointer to the tree path table to construct
188 Output: nodeNum - number of the node containing the key position
189 iterator - BTreeIterator specifying record or insert position
191 Result: noErr - key found, index is record index
192 fsBTRecordNotFoundErr - key not found, index is insert index
193 fsBTEmptyErr - key not found, return params are nil
194 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
195 -------------------------------------------------------------------------------*/
197 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
198 BTreeKeyPtr searchKey
,
199 TreePathTable treePathTable
,
201 BlockDescriptor
*nodePtr
,
202 UInt16
*returnIndex
)
205 SInt16 level
; // Expected depth of current node
206 UInt32 curNodeNum
; // Current node we're searching
210 SInt8 nodeKind
; // Kind of current node (index/leaf)
216 curNodeNum
= btreePtr
->rootNode
;
217 level
= btreePtr
->treeDepth
;
219 if (level
== 0) // is the tree empty?
225 //\80\80 for debugging...
226 treePathTable
[0].node
= 0;
227 treePathTable
[0].index
= 0;
232 // [2550929] Node number 0 is the header node. It is never a valid
233 // index or leaf node. If we're ever asked to search through node 0,
234 // something has gone wrong (typically a bad child node number, or
235 // we found a node full of zeroes that we thought was an index node).
239 // Panic("\pSearchTree: curNodeNum is zero!");
244 err
= GetNode (btreePtr
, curNodeNum
, &nodeRec
);
251 // [2550929] Sanity check the node height and node type. We expect
252 // particular values at each iteration in the search. This checking
253 // quickly finds bad pointers, loops, and other damage to the
254 // hierarchy of the B-tree.
256 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
258 // Panic("\pIncorrect node height");
262 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
265 // Nodes at level 1 must be leaves, by definition
266 if (nodeKind
!= kBTLeafNode
)
268 // Panic("\pIncorrect node type: expected leaf");
275 // A node at any other depth must be an index node
276 if (nodeKind
!= kBTIndexNode
)
278 // Panic("\pIncorrect node type: expected index");
284 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
286 treePathTable
[level
].node
= curNodeNum
;
288 if (nodeKind
== kBTLeafNode
)
290 treePathTable
[level
].index
= index
;
291 break; // were done...
294 if ( (keyFound
!= true) && (index
!= 0))
297 treePathTable
[level
].index
= index
;
299 err
= GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
302 // [2550929] If we got an error, it is probably because the index was bad
303 // (typically a corrupt node that confused SearchNode). Invalidate the node
304 // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
305 // sources call this InvalidateNode.
307 (void) TrashNode(btreePtr
, &nodeRec
);
311 // Get the child pointer out of this index node. We're now done with the current
312 // node and can continue the search with the child node.
313 curNodeNum
= *(UInt32
*)dataPtr
;
314 err
= ReleaseNode (btreePtr
, &nodeRec
);
320 // The child node should be at a level one less than the parent.
324 *nodeNum
= curNodeNum
;
326 *returnIndex
= index
;
329 return noErr
; // searchKey found, index identifies record in node
331 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
334 (void) ReleaseNode(btreePtr
, &nodeRec
);
335 // fall into ErrorExit
340 nodePtr
->buffer
= nil
;
341 nodePtr
->blockHeader
= nil
;
350 ////////////////////////////////// InsertTree ///////////////////////////////////
352 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
353 TreePathTable treePathTable
,
357 BlockDescriptor
*targetNode
,
360 Boolean replacingKey
,
363 InsertKey primaryKey
;
366 primaryKey
.keyPtr
= keyPtr
;
367 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
368 primaryKey
.recPtr
= recPtr
;
369 primaryKey
.recSize
= recSize
;
370 primaryKey
.replacingKey
= replacingKey
;
371 primaryKey
.skipRotate
= false;
373 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
374 targetNode
, index
, level
, insertNode
);
378 } // End of InsertTree
381 ////////////////////////////////// InsertLevel //////////////////////////////////
383 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
384 TreePathTable treePathTable
,
385 InsertKey
*primaryKey
,
386 InsertKey
*secondaryKey
,
387 BlockDescriptor
*targetNode
,
393 BlockDescriptor leftNode
;
394 UInt32 targetNodeNum
;
397 Boolean insertParent
;
398 Boolean updateParent
;
402 #if defined(applec) && !defined(__SC__)
403 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), "\P InsertLevel: non-leaf at level 1! ");
405 leftNode
.buffer
= nil
;
406 leftNode
.blockHeader
= nil
;
407 targetNodeNum
= treePathTable
[level
].node
;
409 insertParent
= false;
410 updateParent
= false;
413 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
415 ////// process first insert //////
417 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
418 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
423 // Extend the treePathTable by adding an entry for the new
424 // root node that references the current targetNode.
426 // If inserting the secondaryKey changes the first key of
427 // the target node, then we'll have to update the second
428 // key in the new root node.
430 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
431 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
435 *insertNode
= newNodeNum
;
437 ////// process second insert (if any) //////
439 if ( secondaryKey
!= nil
)
443 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
444 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
447 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
448 DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
451 //////////////////////// Update Parent(s) ///////////////////////////////
453 if ( insertParent
|| updateParent
)
455 BlockDescriptor parentNode
;
456 UInt32 parentNodeNum
;
461 parentNode
.buffer
= nil
;
462 parentNode
.blockHeader
= nil
;
466 PanicIf ( (level
== btreePtr
->treeDepth
), "\p InsertLevel: unfinished insert!?");
470 // Get Parent Node data...
471 index
= treePathTable
[level
].index
;
472 parentNodeNum
= treePathTable
[level
].node
;
474 PanicIf ( parentNodeNum
== 0, "\p InsertLevel: parent node is zero!?");
476 err
= GetNode (btreePtr
, parentNodeNum
, &parentNode
); // released as target node in next level up
478 #if defined(applec) && !defined(__SC__)
479 if (DEBUG_BUILD
&& level
> 1)
480 PanicIf ( ((NodeDescPtr
)parentNode
.buffer
)->kind
!= kBTIndexNode
, "\P InsertLevel: parent node not an index node! ");
482 ////////////////////////// Update Parent Index //////////////////////////////
487 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
489 //\80\80 debug: check if ptr == targetNodeNum
490 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
491 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p InsertLevel: parent ptr doesn't match target node!");
493 // need to delete and re-insert this parent key/ptr
494 // we delete it here and it gets re-inserted in the
495 // InsertLevel call below.
496 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
498 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
499 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
500 primaryKey
->recPtr
= (UInt8
*) &targetNodeNum
;
501 primaryKey
->recSize
= sizeof(targetNodeNum
);
502 primaryKey
->replacingKey
= kReplaceRecord
;
503 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
506 ////////////////////////// Add New Parent Index /////////////////////////////
510 InsertKey
*insertKeyPtr
;
514 insertKeyPtr
= &insertKey
;
515 secondaryKey
= &insertKey
;
519 insertKeyPtr
= primaryKey
;
522 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
523 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
524 insertKeyPtr
->recPtr
= (UInt8
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
525 insertKeyPtr
->recSize
= sizeof(UInt32
);
526 insertKeyPtr
->replacingKey
= kInsertRecord
;
527 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
530 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
531 &parentNode
, index
, level
, insertNode
);
535 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
538 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
545 (void) ReleaseNode (btreePtr
, targetNode
);
546 (void) ReleaseNode (btreePtr
, &leftNode
);
548 Panic ("\p InsertLevel: an error occurred!");
552 } // End of InsertLevel
556 ////////////////////////////////// InsertNode ///////////////////////////////////
558 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
561 BlockDescriptor
*rightNode
,
568 BlockDescriptor
*leftNode
,
569 Boolean
*updateParent
,
570 Boolean
*insertParent
,
573 BlockDescriptor
*targetNode
;
581 PanicIf ( rightNode
->buffer
== leftNode
->buffer
, "\p InsertNode: rightNode == leftNode, huh?");
583 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
586 /////////////////////// Try Simple Insert ///////////////////////////////
588 if ( node
== leftNodeNum
)
589 targetNode
= leftNode
;
591 targetNode
= rightNode
;
593 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
600 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
601 *updateParent
= true; // the first record changed so we need to update the parent
605 //////////////////////// Try Rotate Left ////////////////////////////////
607 if ( !recordFit
&& leftNodeNum
> 0 )
609 PanicIf ( leftNode
->buffer
!= nil
, "\p InsertNode: leftNode already aquired!");
611 if ( leftNode
->buffer
== nil
)
613 err
= GetNode (btreePtr
, leftNodeNum
, leftNode
); // will be released by caller or a split below
616 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
619 PanicIf ( ((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
, "\p InsertNode, RotateLeft: invalid sibling link!" );
621 if ( !key
->skipRotate
) // are rotates allowed?
623 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
624 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
629 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
630 *updateParent
= true;
636 //////////////////////// Try Split Left /////////////////////////////////
640 // might not have left node...
641 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
642 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
645 // if we split root node - add new root
647 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
649 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
655 *insertParent
= true;
657 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
658 *updateParent
= true;
665 (void) ReleaseNode (btreePtr
, leftNode
);
668 } // End of InsertNode
671 /*-------------------------------------------------------------------------------
672 Routine: DeleteTree - One_line_description.
674 Function: Brief_description_of_the_function_and_any_side_effects
678 Input: btreePtr - description
679 treePathTable - description
680 targetNode - description
683 Result: noErr - success
685 -------------------------------------------------------------------------------*/
687 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
688 TreePathTable treePathTable
,
689 BlockDescriptor
*targetNode
,
694 BlockDescriptor parentNode
;
695 BTNodeDescriptor
*targetNodePtr
;
696 UInt32 targetNodeNum
;
697 Boolean deleteRequired
;
698 Boolean updateRequired
;
700 // XXXdbg - initialize these to null in case we get an
701 // error and try to exit before it's initialized
702 parentNode
.buffer
= nil
;
703 parentNode
.blockHeader
= nil
;
705 deleteRequired
= false;
706 updateRequired
= false;
708 targetNodeNum
= treePathTable
[level
].node
;
709 targetNodePtr
= targetNode
->buffer
;
710 PanicIf (targetNodePtr
== nil
, "\pDeleteTree: targetNode has nil buffer!");
713 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
715 DeleteRecord (btreePtr
, targetNodePtr
, index
);
717 //\80\80 coalesce remaining records?
719 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
721 BlockDescriptor siblingNode
;
722 UInt32 siblingNodeNum
;
724 deleteRequired
= true;
726 siblingNode
.buffer
= nil
;
727 siblingNode
.blockHeader
= nil
;
729 ////////////////// Get Siblings & Update Links //////////////////////////
731 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
732 if ( siblingNodeNum
!= 0 )
734 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
738 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
740 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
741 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
744 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
746 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
749 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
750 if ( siblingNodeNum
!= 0 )
752 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
756 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
758 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
759 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
762 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
764 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
767 //////////////////////// Free Empty Node ////////////////////////////////
769 ClearNode (btreePtr
, targetNodePtr
);
771 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
774 err
= FreeNode (btreePtr
, targetNodeNum
);
777 else if ( index
== 0 ) // did we delete the first record?
779 updateRequired
= true; // yes, so we need to update parent
783 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
785 deleteRequired
= false;
786 updateRequired
= false;
788 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
790 btreePtr
->rootNode
= 0;
791 btreePtr
->treeDepth
= 0;
793 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
795 err
= CollapseTree (btreePtr
, targetNode
);
801 if ( updateRequired
|| deleteRequired
)
803 ++level
; // next level
805 //// Get Parent Node and index
806 index
= treePathTable
[level
].index
;
807 err
= GetNode (btreePtr
, treePathTable
[level
].node
, &parentNode
);
810 if ( updateRequired
)
818 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
820 //\80\80 debug: check if ptr == targetNodeNum
821 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
822 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
824 // need to delete and re-insert this parent key/ptr
825 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
827 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
828 recPtr
= (UInt8
*) &targetNodeNum
;
829 recSize
= sizeof(targetNodeNum
);
831 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
832 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
835 else // deleteRequired
837 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
843 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
850 (void) ReleaseNode (btreePtr
, targetNode
);
851 (void) ReleaseNode (btreePtr
, &parentNode
);
859 ///////////////////////////////// CollapseTree //////////////////////////////////
861 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
862 BlockDescriptor
*blockPtr
)
868 originalRoot
= btreePtr
->rootNode
;
871 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
875 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
876 break; // this will make a fine root node
878 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
879 break; // we've hit bottom
881 nodeNum
= btreePtr
->rootNode
;
882 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
883 --btreePtr
->treeDepth
;
885 //// Clear and Free Current Old Root Node ////
886 ClearNode (btreePtr
, blockPtr
->buffer
);
887 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
889 err
= FreeNode (btreePtr
, nodeNum
);
892 //// Get New Root Node
893 err
= GetNode (btreePtr
, btreePtr
->rootNode
, blockPtr
);
897 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
900 if (btreePtr
->rootNode
!= originalRoot
)
901 M_BTreeHeaderDirty (btreePtr
);
903 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
909 /////////////////////////////////// ErrorExit ///////////////////////////////////
912 (void) ReleaseNode (btreePtr
, blockPtr
);
918 ////////////////////////////////// RotateLeft ///////////////////////////////////
920 /*-------------------------------------------------------------------------------
922 Routine: RotateLeft - One_line_description.
924 Function: Brief_description_of_the_function_and_any_side_effects
926 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
928 Input: btreePtr - description
929 leftNode - description
930 rightNode - description
931 rightInsertIndex - description
934 recSize - description
937 insertNodeNum - description
938 recordFit - description
941 Result: noErr - success
943 -------------------------------------------------------------------------------*/
945 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
946 NodeDescPtr leftNode
,
947 NodeDescPtr rightNode
,
948 UInt16 rightInsertIndex
,
953 UInt32
*insertNodeNum
,
955 UInt16
*recsRotated
)
960 SInt32 leftSize
, rightSize
;
963 UInt16 lengthFieldSize
;
964 UInt16 index
, moveIndex
;
967 ///////////////////// Determine If Record Will Fit //////////////////////////
969 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
971 // the key's length field is 8-bits in HFS and 16-bits in HFS+
972 if ( btreePtr
->attributes
& kBTBigKeysMask
)
973 lengthFieldSize
= sizeof(UInt16
);
975 lengthFieldSize
= sizeof(UInt8
);
977 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
979 if ( M_IsOdd (insertSize
) )
980 ++insertSize
; // add pad byte;
982 nodeSize
= btreePtr
->nodeSize
;
984 // add size of insert record to right node
985 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
986 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
990 while ( leftSize
< rightSize
)
992 if ( moveIndex
< rightInsertIndex
)
994 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
996 else if ( moveIndex
== rightInsertIndex
)
998 moveSize
= insertSize
;
1000 else // ( moveIndex > rightInsertIndex )
1002 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
1005 leftSize
+= moveSize
;
1006 rightSize
-= moveSize
;
1010 if ( leftSize
> nodeSize
) // undo last move
1012 leftSize
-= moveSize
;
1013 rightSize
+= moveSize
;
1017 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
1027 // we've found balance point, moveIndex == number of records moved into leftNode
1030 //////////////////////////// Rotate Records /////////////////////////////////
1032 *recsRotated
= moveIndex
;
1036 while ( index
< moveIndex
)
1038 if ( index
== rightInsertIndex
) // insert new record in left node
1040 UInt16 leftInsertIndex
;
1042 leftInsertIndex
= leftNode
->numRecords
;
1044 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
1045 keyPtr
, keyLength
, recPtr
, recSize
);
1048 Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
1049 err
= fsBTBadRotateErr
;
1053 *insertIndex
= leftInsertIndex
;
1054 *insertNodeNum
= rightNode
->bLink
;
1058 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1061 Panic ("\pRotateLeft: RotateRecordLeft returned false!");
1062 err
= fsBTBadRotateErr
;
1070 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1072 rightInsertIndex
-= index
; // adjust for records already rotated
1074 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1075 keyPtr
, keyLength
, recPtr
, recSize
);
1078 Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
1079 err
= fsBTBadRotateErr
;
1083 *insertIndex
= rightInsertIndex
;
1084 *insertNodeNum
= leftNode
->fLink
;
1091 ////////////////////////////// Error Exit ///////////////////////////////////
1105 /////////////////////////////////// SplitLeft ///////////////////////////////////
1107 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1108 BlockDescriptor
*leftNode
,
1109 BlockDescriptor
*rightNode
,
1110 UInt32 rightNodeNum
,
1115 UInt16
*insertIndex
,
1116 UInt32
*insertNodeNum
,
1117 UInt16
*recsRotated
)
1120 NodeDescPtr left
, right
;
1125 ///////////////////////////// Compare Nodes /////////////////////////////////
1127 right
= rightNode
->buffer
;
1128 left
= leftNode
->buffer
;
1130 PanicIf ( right
->bLink
!= 0 && left
== 0, "\p SplitLeft: left sibling missing!?" );
1132 /* type should be kBTLeafNode or kBTIndexNode */
1134 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1135 return fsBTInvalidNodeErr
;
1139 if ( left
->fLink
!= rightNodeNum
)
1140 return fsBTInvalidNodeErr
; //\80\80 E_BadSibling ?
1142 if ( left
->height
!= right
->height
)
1143 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeHeight ?
1145 if ( left
->kind
!= right
->kind
)
1146 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeType ?
1150 ///////////////////////////// Allocate Node /////////////////////////////////
1152 err
= AllocateNode (btreePtr
, &newNodeNum
);
1153 M_ExitOnError (err
);
1156 /////////////// Update Forward Link In Original Left Node ///////////////////
1161 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1163 left
->fLink
= newNodeNum
;
1164 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1165 M_ExitOnError (err
);
1169 /////////////////////// Initialize New Left Node ////////////////////////////
1171 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1172 M_ExitOnError (err
);
1175 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1177 left
= leftNode
->buffer
;
1178 left
->fLink
= rightNodeNum
;
1181 // Steal Info From Right Node
1183 left
->bLink
= right
->bLink
;
1184 left
->kind
= right
->kind
;
1185 left
->height
= right
->height
;
1187 right
->bLink
= newNodeNum
; // update Right bLink
1189 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1191 // if we're adding a new first leaf node - update BTreeInfoRec
1193 btreePtr
->firstLeafNode
= newNodeNum
;
1194 M_BTreeHeaderDirty (btreePtr
); //\80\80 AllocateNode should have set the bit already...
1197 ////////////////////////////// Rotate Left //////////////////////////////////
1199 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1200 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1202 M_ExitOnError (err
);
1208 (void) ReleaseNode (btreePtr
, leftNode
);
1209 (void) ReleaseNode (btreePtr
, rightNode
);
1211 //\80\80 Free new node if allocated?
1222 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1224 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1225 NodeDescPtr leftNode
,
1226 NodeDescPtr rightNode
)
1232 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1233 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1235 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1240 DeleteRecord (btreePtr
, rightNode
, 0);
1246 //////////////////////////////// AddNewRootNode /////////////////////////////////
1248 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1249 NodeDescPtr leftNode
,
1250 NodeDescPtr rightNode
)
1253 BlockDescriptor rootNode
;
1259 rootNode
.buffer
= nil
;
1260 rootNode
.blockHeader
= nil
;
1262 PanicIf (leftNode
== nil
, "\pAddNewRootNode: leftNode == nil");
1263 PanicIf (rightNode
== nil
, "\pAddNewRootNode: rightNode == nil");
1266 /////////////////////// Initialize New Root Node ////////////////////////////
1268 err
= AllocateNode (btreePtr
, &rootNum
);
1269 M_ExitOnError (err
);
1271 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1272 M_ExitOnError (err
);
1275 ModifyBlockStart(btreePtr
->fileRefNum
, &rootNode
);
1277 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1278 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1281 ///////////////////// Insert Left Node Index Record /////////////////////////
1283 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1284 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1286 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1287 (UInt8
*) &rightNode
->bLink
, 4 );
1289 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1292 //////////////////// Insert Right Node Index Record /////////////////////////
1294 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1295 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1297 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1298 (UInt8
*) &leftNode
->fLink
, 4 );
1300 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1303 /////////////////////////// Release Root Node ///////////////////////////////
1305 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1306 M_ExitOnError (err
);
1308 // update BTreeInfoRec
1310 btreePtr
->rootNode
= rootNum
;
1311 btreePtr
->flags
|= kBTHeaderDirty
;
1316 ////////////////////////////// Error Exit ///////////////////////////////////
1324 static UInt16
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1328 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1329 length
= KeyLength (btreePtr
, key
); // just use actual key length
1331 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //\80\80 shouldn't we clear the pad bytes?