2 * Copyright (c) 2000-2008 Apple 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"
98 #include "../../hfs_btreeio.h"
101 /////////////////////// Routines Internal To BTree Module ///////////////////////
106 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
108 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
109 NodeDescPtr leftNode
,
110 NodeDescPtr rightNode
);
112 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
113 BlockDescriptor
*blockPtr
);
115 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
116 NodeDescPtr leftNode
,
117 NodeDescPtr rightNode
,
118 u_int16_t rightInsertIndex
,
122 u_int16_t
*insertIndex
,
123 u_int32_t
*insertNodeNum
,
125 u_int16_t
*recsRotated
);
127 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
128 NodeDescPtr leftNode
,
129 NodeDescPtr rightNode
);
131 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
132 BlockDescriptor
*leftNode
,
133 BlockDescriptor
*rightNode
,
134 u_int32_t rightNodeNum
,
139 u_int16_t
*insertIndex
,
140 u_int32_t
*insertNodeNum
,
141 u_int16_t
*recsRotated
);
145 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
146 TreePathTable treePathTable
,
147 InsertKey
*primaryKey
,
148 InsertKey
*secondaryKey
,
149 BlockDescriptor
*targetNode
,
152 u_int32_t
*insertNode
);
154 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
156 BlockDescriptor
*rightNode
,
161 BlockDescriptor
*leftNode
,
162 Boolean
*updateParent
,
163 Boolean
*insertParent
,
164 Boolean
*rootSplit
);
166 static u_int16_t
GetKeyLength (const BTreeControlBlock
*btreePtr
,
168 Boolean forLeafNode
);
172 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
175 /*-------------------------------------------------------------------------------
177 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
179 Function: Searches BTree for specified key, setting up the Tree Path Table to
180 reflect the search path.
183 Input: btreePtr - pointer to control block of BTree to search
184 keyPtr - pointer to the key to search for
185 treePathTable - pointer to the tree path table to construct
187 Output: nodeNum - number of the node containing the key position
188 iterator - BTreeIterator specifying record or insert position
190 Result: noErr - key found, index is record index
191 fsBTRecordNotFoundErr - key not found, index is insert index
192 fsBTEmptyErr - key not found, return params are nil
193 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
194 -------------------------------------------------------------------------------*/
196 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
197 BTreeKeyPtr searchKey
,
198 TreePathTable treePathTable
,
200 BlockDescriptor
*nodePtr
,
201 u_int16_t
*returnIndex
)
204 int16_t level
; // Expected depth of current node
205 u_int32_t curNodeNum
; // Current node we're searching
209 int8_t nodeKind
; // Kind of current node (index/leaf)
215 curNodeNum
= btreePtr
->rootNode
;
216 level
= btreePtr
->treeDepth
;
218 if (level
== 0) // is the tree empty?
224 //\80\80 for debugging...
225 treePathTable
[0].node
= 0;
226 treePathTable
[0].index
= 0;
231 // [2550929] Node number 0 is the header node. It is never a valid
232 // index or leaf node. If we're ever asked to search through node 0,
233 // something has gone wrong (typically a bad child node number, or
234 // we found a node full of zeroes that we thought was an index node).
238 // Panic("SearchTree: curNodeNum is zero!");
243 err
= GetNode (btreePtr
, curNodeNum
, 0, &nodeRec
);
250 // [2550929] Sanity check the node height and node type. We expect
251 // particular values at each iteration in the search. This checking
252 // quickly finds bad pointers, loops, and other damage to the
253 // hierarchy of the B-tree.
255 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
257 // Panic("Incorrect node height");
261 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
264 // Nodes at level 1 must be leaves, by definition
265 if (nodeKind
!= kBTLeafNode
)
267 // Panic("Incorrect node type: expected leaf");
274 // A node at any other depth must be an index node
275 if (nodeKind
!= kBTIndexNode
)
277 // Panic("Incorrect node type: expected index");
283 keyFound
= SearchNode (btreePtr
, nodeRec
.buffer
, searchKey
, &index
);
285 treePathTable
[level
].node
= curNodeNum
;
287 if (nodeKind
== kBTLeafNode
)
289 treePathTable
[level
].index
= index
;
290 break; // were done...
293 if ( (keyFound
!= true) && (index
!= 0))
296 treePathTable
[level
].index
= index
;
298 err
= GetRecordByIndex (btreePtr
, nodeRec
.buffer
, index
, &keyPtr
, &dataPtr
, &dataSize
);
301 // [2550929] If we got an error, it is probably because the index was bad
302 // (typically a corrupt node that confused SearchNode). Invalidate the node
303 // so we won't accidentally use the corrupted contents. NOTE: the Mac OS 9
304 // sources call this InvalidateNode.
306 (void) TrashNode(btreePtr
, &nodeRec
);
310 // Get the child pointer out of this index node. We're now done with the current
311 // node and can continue the search with the child node.
312 curNodeNum
= *(u_int32_t
*)dataPtr
;
313 err
= ReleaseNode (btreePtr
, &nodeRec
);
319 // The child node should be at a level one less than the parent.
323 *nodeNum
= curNodeNum
;
325 *returnIndex
= index
;
328 return noErr
; // searchKey found, index identifies record in node
330 return fsBTRecordNotFoundErr
; // searchKey not found, index identifies insert point
333 (void) ReleaseNode(btreePtr
, &nodeRec
);
334 // fall into ErrorExit
339 nodePtr
->buffer
= nil
;
340 nodePtr
->blockHeader
= nil
;
349 ////////////////////////////////// InsertTree ///////////////////////////////////
351 OSStatus
InsertTree ( BTreeControlBlockPtr btreePtr
,
352 TreePathTable treePathTable
,
356 BlockDescriptor
*targetNode
,
359 Boolean replacingKey
,
360 u_int32_t
*insertNode
)
362 InsertKey primaryKey
;
365 primaryKey
.keyPtr
= keyPtr
;
366 primaryKey
.keyLength
= GetKeyLength(btreePtr
, primaryKey
.keyPtr
, (level
== 1));
367 primaryKey
.recPtr
= recPtr
;
368 primaryKey
.recSize
= recSize
;
369 primaryKey
.replacingKey
= replacingKey
;
370 primaryKey
.skipRotate
= false;
372 err
= InsertLevel (btreePtr
, treePathTable
, &primaryKey
, nil
,
373 targetNode
, index
, level
, insertNode
);
377 } // End of InsertTree
380 ////////////////////////////////// InsertLevel //////////////////////////////////
382 OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
383 TreePathTable treePathTable
,
384 InsertKey
*primaryKey
,
385 InsertKey
*secondaryKey
,
386 BlockDescriptor
*targetNode
,
389 u_int32_t
*insertNode
)
392 BlockDescriptor leftNode
;
393 u_int32_t targetNodeNum
;
394 u_int32_t newNodeNum
;
396 Boolean insertParent
;
397 Boolean updateParent
;
401 #if defined(applec) && !defined(__SC__)
402 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), " InsertLevel: non-leaf at level 1! ");
404 leftNode
.buffer
= nil
;
405 leftNode
.blockHeader
= nil
;
406 targetNodeNum
= treePathTable
[level
].node
;
408 insertParent
= false;
409 updateParent
= false;
412 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
414 ////// process first insert //////
416 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
417 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &newRoot
);
422 // Extend the treePathTable by adding an entry for the new
423 // root node that references the current targetNode.
425 // If inserting the secondaryKey changes the first key of
426 // the target node, then we'll have to update the second
427 // key in the new root node.
429 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
430 treePathTable
[level
+ 1].index
= 1; // 1 since we always split/rotate left
434 *insertNode
= newNodeNum
;
436 ////// process second insert (if any) //////
438 if ( secondaryKey
!= nil
)
442 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
,
443 &newNodeNum
, &newIndex
, &leftNode
, &updateParent
, &insertParent
, &temp
);
446 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
447 DebugStr(" InsertLevel: New root from primary key, update from secondary key...");
450 //////////////////////// Update Parent(s) ///////////////////////////////
452 if ( insertParent
|| updateParent
)
454 BlockDescriptor parentNode
;
455 u_int32_t parentNodeNum
;
460 parentNode
.buffer
= nil
;
461 parentNode
.blockHeader
= nil
;
465 PanicIf ( (level
== btreePtr
->treeDepth
), " InsertLevel: unfinished insert!?");
469 // Get Parent Node data...
470 index
= treePathTable
[level
].index
;
471 parentNodeNum
= treePathTable
[level
].node
;
473 PanicIf ( parentNodeNum
== 0, " InsertLevel: parent node is zero!?");
475 err
= GetNode (btreePtr
, parentNodeNum
, 0, &parentNode
); // released as target node in next level up
477 #if defined(applec) && !defined(__SC__)
478 if (DEBUG_BUILD
&& level
> 1)
479 PanicIf ( ((NodeDescPtr
)parentNode
.buffer
)->kind
!= kBTIndexNode
, " InsertLevel: parent node not an index node! ");
481 ////////////////////////// Update Parent Index //////////////////////////////
486 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
488 //\80\80 debug: check if ptr == targetNodeNum
489 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
490 PanicIf( (*(u_int32_t
*) recPtr
) != targetNodeNum
, " InsertLevel: parent ptr doesn't match target node!");
492 // need to delete and re-insert this parent key/ptr
493 // we delete it here and it gets re-inserted in the
494 // InsertLevel call below.
495 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
497 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
498 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
499 primaryKey
->recPtr
= (u_int8_t
*) &targetNodeNum
;
500 primaryKey
->recSize
= sizeof(targetNodeNum
);
501 primaryKey
->replacingKey
= kReplaceRecord
;
502 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
505 ////////////////////////// Add New Parent Index /////////////////////////////
509 InsertKey
*insertKeyPtr
;
513 insertKeyPtr
= &insertKey
;
514 secondaryKey
= &insertKey
;
518 insertKeyPtr
= primaryKey
;
521 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
.buffer
, 0);
522 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
523 insertKeyPtr
->recPtr
= (u_int8_t
*) &((NodeDescPtr
)targetNode
->buffer
)->bLink
;
524 insertKeyPtr
->recSize
= sizeof(u_int32_t
);
525 insertKeyPtr
->replacingKey
= kInsertRecord
;
526 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
529 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
530 &parentNode
, index
, level
, insertNode
);
534 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
); // all done with target
537 err
= UpdateNode (btreePtr
, &leftNode
, 0, kLockTransaction
); // all done with left sibling
544 (void) ReleaseNode (btreePtr
, targetNode
);
545 (void) ReleaseNode (btreePtr
, &leftNode
);
547 Panic (" InsertLevel: an error occurred!");
551 } // End of InsertLevel
555 ////////////////////////////////// InsertNode ///////////////////////////////////
557 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
560 BlockDescriptor
*rightNode
,
567 BlockDescriptor
*leftNode
,
568 Boolean
*updateParent
,
569 Boolean
*insertParent
,
572 BlockDescriptor
*targetNode
;
573 u_int32_t leftNodeNum
;
574 u_int16_t recsRotated
;
580 PanicIf ( rightNode
->buffer
== leftNode
->buffer
, " InsertNode: rightNode == leftNode, huh?");
582 leftNodeNum
= ((NodeDescPtr
) rightNode
->buffer
)->bLink
;
585 /////////////////////// Try Simple Insert ///////////////////////////////
587 /* sanity check our left and right nodes here. */
588 if (node
== leftNodeNum
) {
589 if (leftNode
->buffer
== NULL
) {
590 err
= fsBTInvalidNodeErr
;
594 targetNode
= leftNode
;
598 // we can assume right node is initialized.
599 targetNode
= rightNode
;
603 recordFit
= InsertKeyRecord (btreePtr
, targetNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
610 if ( (index
== 0) && (((NodeDescPtr
) targetNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
611 *updateParent
= true; // the first record changed so we need to update the parent
615 //////////////////////// Try Rotate Left ////////////////////////////////
617 if ( !recordFit
&& leftNodeNum
> 0 )
619 PanicIf ( leftNode
->buffer
!= nil
, " InsertNode: leftNode already acquired!");
621 if ( leftNode
->buffer
== nil
)
623 err
= GetNode (btreePtr
, leftNodeNum
, 0, leftNode
); // will be released by caller or a split below
626 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
629 PanicIf ( ((NodeDescPtr
) leftNode
->buffer
)->fLink
!= node
, " InsertNode, RotateLeft: invalid sibling link!" );
631 if ( !key
->skipRotate
) // are rotates allowed?
633 err
= RotateLeft (btreePtr
, leftNode
->buffer
, rightNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
634 key
->recSize
, newIndex
, newNode
, &recordFit
, &recsRotated
);
639 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
640 *updateParent
= true;
646 //////////////////////// Try Split Left /////////////////////////////////
650 // might not have left node...
651 err
= SplitLeft (btreePtr
, leftNode
, rightNode
, node
, index
, key
->keyPtr
,
652 key
->recPtr
, key
->recSize
, newIndex
, newNode
, &recsRotated
);
655 // if we split root node - add new root
657 if ( ((NodeDescPtr
) rightNode
->buffer
)->height
== btreePtr
->treeDepth
)
659 err
= AddNewRootNode (btreePtr
, leftNode
->buffer
, rightNode
->buffer
); // Note: does not update TPT
665 *insertParent
= true;
667 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
668 *updateParent
= true;
675 (void) ReleaseNode (btreePtr
, leftNode
);
678 } // End of InsertNode
681 /*-------------------------------------------------------------------------------
682 Routine: DeleteTree - One_line_description.
684 Function: Brief_description_of_the_function_and_any_side_effects
688 Input: btreePtr - description
689 treePathTable - description
690 targetNode - description
693 Result: noErr - success
695 -------------------------------------------------------------------------------*/
697 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
698 TreePathTable treePathTable
,
699 BlockDescriptor
*targetNode
,
704 BlockDescriptor parentNode
;
705 BTNodeDescriptor
*targetNodePtr
;
706 u_int32_t targetNodeNum
;
707 Boolean deleteRequired
;
708 Boolean updateRequired
;
710 // XXXdbg - initialize these to null in case we get an
711 // error and try to exit before it's initialized
712 parentNode
.buffer
= nil
;
713 parentNode
.blockHeader
= nil
;
715 deleteRequired
= false;
716 updateRequired
= false;
718 targetNodeNum
= treePathTable
[level
].node
;
719 targetNodePtr
= targetNode
->buffer
;
720 PanicIf (targetNodePtr
== nil
, "DeleteTree: targetNode has nil buffer!");
723 ModifyBlockStart(btreePtr
->fileRefNum
, targetNode
);
725 DeleteRecord (btreePtr
, targetNodePtr
, index
);
727 //\80\80 coalesce remaining records?
729 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
731 BlockDescriptor siblingNode
;
732 u_int32_t siblingNodeNum
;
734 deleteRequired
= true;
736 siblingNode
.buffer
= nil
;
737 siblingNode
.blockHeader
= nil
;
739 ////////////////// Get Siblings & Update Links //////////////////////////
741 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
742 if ( siblingNodeNum
!= 0 )
744 err
= GetNode (btreePtr
, siblingNodeNum
, 0, &siblingNode
);
748 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
750 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
751 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
754 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update firstLeafNode
756 btreePtr
->firstLeafNode
= targetNodePtr
->fLink
;
759 siblingNodeNum
= targetNodePtr
->fLink
; // Right Sibling Node
760 if ( siblingNodeNum
!= 0 )
762 err
= GetNode (btreePtr
, siblingNodeNum
, 0, &siblingNode
);
766 ModifyBlockStart(btreePtr
->fileRefNum
, &siblingNode
);
768 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
769 err
= UpdateNode (btreePtr
, &siblingNode
, 0, kLockTransaction
);
772 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
774 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
777 //////////////////////// Free Empty Node ////////////////////////////////
779 ClearNode (btreePtr
, targetNodePtr
);
781 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
784 err
= FreeNode (btreePtr
, targetNodeNum
);
787 else if ( index
== 0 ) // did we delete the first record?
789 updateRequired
= true; // yes, so we need to update parent
793 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
795 deleteRequired
= false;
796 updateRequired
= false;
798 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
800 btreePtr
->rootNode
= 0;
801 btreePtr
->treeDepth
= 0;
803 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
805 err
= CollapseTree (btreePtr
, targetNode
);
811 if ( updateRequired
|| deleteRequired
)
813 ++level
; // next level
815 //// Get Parent Node and index
816 index
= treePathTable
[level
].index
;
817 err
= GetNode (btreePtr
, treePathTable
[level
].node
, 0, &parentNode
);
820 if ( updateRequired
)
825 u_int32_t insertNode
;
828 ModifyBlockStart(btreePtr
->fileRefNum
, &parentNode
);
830 //\80\80 debug: check if ptr == targetNodeNum
831 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
832 PanicIf( (*(u_int32_t
*) recPtr
) != targetNodeNum
, " DeleteTree: parent ptr doesn't match targetNodeNum!!");
834 // need to delete and re-insert this parent key/ptr
835 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
837 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
838 recPtr
= (u_int8_t
*) &targetNodeNum
;
839 recSize
= sizeof(targetNodeNum
);
841 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
842 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
845 else // deleteRequired
847 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
853 err
= UpdateNode (btreePtr
, targetNode
, 0, kLockTransaction
);
860 (void) ReleaseNode (btreePtr
, targetNode
);
861 (void) ReleaseNode (btreePtr
, &parentNode
);
869 ///////////////////////////////// CollapseTree //////////////////////////////////
871 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
872 BlockDescriptor
*blockPtr
)
875 u_int32_t originalRoot
;
878 originalRoot
= btreePtr
->rootNode
;
881 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
885 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
886 break; // this will make a fine root node
888 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
889 break; // we've hit bottom
891 nodeNum
= btreePtr
->rootNode
;
892 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
893 --btreePtr
->treeDepth
;
895 //// Clear and Free Current Old Root Node ////
896 ClearNode (btreePtr
, blockPtr
->buffer
);
897 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
);
899 err
= FreeNode (btreePtr
, nodeNum
);
902 //// Get New Root Node
903 err
= GetNode (btreePtr
, btreePtr
->rootNode
, 0, blockPtr
);
907 ModifyBlockStart(btreePtr
->fileRefNum
, blockPtr
);
910 if (btreePtr
->rootNode
!= originalRoot
)
911 M_BTreeHeaderDirty (btreePtr
);
913 err
= UpdateNode (btreePtr
, blockPtr
, 0, kLockTransaction
); // always update!
919 /////////////////////////////////// ErrorExit ///////////////////////////////////
922 (void) ReleaseNode (btreePtr
, blockPtr
);
928 ////////////////////////////////// RotateLeft ///////////////////////////////////
930 /*-------------------------------------------------------------------------------
932 Routine: RotateLeft - One_line_description.
934 Function: Brief_description_of_the_function_and_any_side_effects
936 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
938 Input: btreePtr - description
939 leftNode - description
940 rightNode - description
941 rightInsertIndex - description
944 recSize - description
947 insertNodeNum - description
948 recordFit - description
951 Result: noErr - success
953 -------------------------------------------------------------------------------*/
955 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
956 NodeDescPtr leftNode
,
957 NodeDescPtr rightNode
,
958 u_int16_t rightInsertIndex
,
962 u_int16_t
*insertIndex
,
963 u_int32_t
*insertNodeNum
,
965 u_int16_t
*recsRotated
)
970 int32_t leftSize
, rightSize
;
971 int32_t moveSize
= 0;
973 u_int16_t lengthFieldSize
;
974 u_int16_t index
, moveIndex
;
977 ///////////////////// Determine If Record Will Fit //////////////////////////
979 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
981 // the key's length field is 8-bits in HFS and 16-bits in HFS+
982 if ( btreePtr
->attributes
& kBTBigKeysMask
)
983 lengthFieldSize
= sizeof(u_int16_t
);
985 lengthFieldSize
= sizeof(u_int8_t
);
987 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(u_int16_t
);
989 if ( M_IsOdd (insertSize
) )
990 ++insertSize
; // add pad byte;
992 nodeSize
= btreePtr
->nodeSize
;
994 // add size of insert record to right node
995 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
996 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
1000 while ( leftSize
< rightSize
)
1002 if ( moveIndex
< rightInsertIndex
)
1004 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
1006 else if ( moveIndex
== rightInsertIndex
)
1008 moveSize
= insertSize
;
1010 else // ( moveIndex > rightInsertIndex )
1012 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
1015 leftSize
+= moveSize
;
1016 rightSize
-= moveSize
;
1020 if ( leftSize
> nodeSize
) // undo last move
1022 leftSize
-= moveSize
;
1023 rightSize
+= moveSize
;
1027 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
1037 // we've found balance point, moveIndex == number of records moved into leftNode
1040 //////////////////////////// Rotate Records /////////////////////////////////
1042 *recsRotated
= moveIndex
;
1046 while ( index
< moveIndex
)
1048 if ( index
== rightInsertIndex
) // insert new record in left node
1050 u_int16_t leftInsertIndex
;
1052 leftInsertIndex
= leftNode
->numRecords
;
1054 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
1055 keyPtr
, keyLength
, recPtr
, recSize
);
1058 Panic ("RotateLeft: InsertKeyRecord (left) returned false!");
1059 err
= fsBTBadRotateErr
;
1063 *insertIndex
= leftInsertIndex
;
1064 *insertNodeNum
= rightNode
->bLink
;
1068 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1071 Panic ("RotateLeft: RotateRecordLeft returned false!");
1072 err
= fsBTBadRotateErr
;
1080 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1082 rightInsertIndex
-= index
; // adjust for records already rotated
1084 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1085 keyPtr
, keyLength
, recPtr
, recSize
);
1088 Panic ("RotateLeft: InsertKeyRecord (right) returned false!");
1089 err
= fsBTBadRotateErr
;
1093 *insertIndex
= rightInsertIndex
;
1094 *insertNodeNum
= leftNode
->fLink
;
1101 ////////////////////////////// Error Exit ///////////////////////////////////
1115 /////////////////////////////////// SplitLeft ///////////////////////////////////
1117 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1118 BlockDescriptor
*leftNode
,
1119 BlockDescriptor
*rightNode
,
1120 u_int32_t rightNodeNum
,
1125 u_int16_t
*insertIndex
,
1126 u_int32_t
*insertNodeNum
,
1127 u_int16_t
*recsRotated
)
1130 NodeDescPtr left
, right
;
1131 u_int32_t newNodeNum
;
1135 ///////////////////////////// Compare Nodes /////////////////////////////////
1137 right
= rightNode
->buffer
;
1138 left
= leftNode
->buffer
;
1140 PanicIf ( right
->bLink
!= 0 && left
== 0, " SplitLeft: left sibling missing!?" );
1142 /* type should be kBTLeafNode or kBTIndexNode */
1144 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1145 return fsBTInvalidNodeErr
;
1149 if ( left
->fLink
!= rightNodeNum
)
1150 return fsBTInvalidNodeErr
; //\80\80 E_BadSibling ?
1152 if ( left
->height
!= right
->height
)
1153 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeHeight ?
1155 if ( left
->kind
!= right
->kind
)
1156 return fsBTInvalidNodeErr
; //\80\80 E_BadNodeType ?
1160 ///////////////////////////// Allocate Node /////////////////////////////////
1162 err
= AllocateNode (btreePtr
, &newNodeNum
);
1163 M_ExitOnError (err
);
1166 /////////////// Update Forward Link In Original Left Node ///////////////////
1171 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1173 left
->fLink
= newNodeNum
;
1174 err
= UpdateNode (btreePtr
, leftNode
, 0, kLockTransaction
);
1175 M_ExitOnError (err
);
1179 /////////////////////// Initialize New Left Node ////////////////////////////
1181 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1182 M_ExitOnError (err
);
1185 ModifyBlockStart(btreePtr
->fileRefNum
, leftNode
);
1187 left
= leftNode
->buffer
;
1188 left
->fLink
= rightNodeNum
;
1191 // Steal Info From Right Node
1193 left
->bLink
= right
->bLink
;
1194 left
->kind
= right
->kind
;
1195 left
->height
= right
->height
;
1197 right
->bLink
= newNodeNum
; // update Right bLink
1199 if ( (left
->kind
== kBTLeafNode
) && (left
->bLink
== 0) )
1201 // if we're adding a new first leaf node - update BTreeInfoRec
1203 btreePtr
->firstLeafNode
= newNodeNum
;
1204 M_BTreeHeaderDirty (btreePtr
); //\80\80 AllocateNode should have set the bit already...
1207 ////////////////////////////// Rotate Left //////////////////////////////////
1209 err
= RotateLeft (btreePtr
, left
, right
, index
, keyPtr
, recPtr
, recSize
,
1210 insertIndex
, insertNodeNum
, &recordFit
, recsRotated
);
1212 M_ExitOnError (err
);
1218 (void) ReleaseNode (btreePtr
, leftNode
);
1219 (void) ReleaseNode (btreePtr
, rightNode
);
1221 //\80\80 Free new node if allocated?
1232 /////////////////////////////// RotateRecordLeft ////////////////////////////////
1234 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
1235 NodeDescPtr leftNode
,
1236 NodeDescPtr rightNode
)
1242 size
= GetRecordSize (btreePtr
, rightNode
, 0);
1243 recPtr
= GetRecordAddress (btreePtr
, rightNode
, 0);
1245 recordFit
= InsertRecord (btreePtr
, leftNode
, leftNode
->numRecords
, recPtr
, size
);
1250 DeleteRecord (btreePtr
, rightNode
, 0);
1256 //////////////////////////////// AddNewRootNode /////////////////////////////////
1258 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
1259 NodeDescPtr leftNode
,
1260 NodeDescPtr rightNode
)
1263 BlockDescriptor rootNode
;
1267 u_int16_t keyLength
;
1269 rootNode
.buffer
= nil
;
1270 rootNode
.blockHeader
= nil
;
1272 PanicIf (leftNode
== nil
, "AddNewRootNode: leftNode == nil");
1273 PanicIf (rightNode
== nil
, "AddNewRootNode: rightNode == nil");
1276 /////////////////////// Initialize New Root Node ////////////////////////////
1278 err
= AllocateNode (btreePtr
, &rootNum
);
1279 M_ExitOnError (err
);
1281 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1282 M_ExitOnError (err
);
1285 ModifyBlockStart(btreePtr
->fileRefNum
, &rootNode
);
1287 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1288 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1291 ///////////////////// Insert Left Node Index Record /////////////////////////
1293 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1294 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1296 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1297 (u_int8_t
*) &rightNode
->bLink
, 4 );
1299 PanicIf ( !didItFit
, "AddNewRootNode:InsertKeyRecord failed for left index record");
1302 //////////////////// Insert Right Node Index Record /////////////////////////
1304 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1305 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1307 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1308 (u_int8_t
*) &leftNode
->fLink
, 4 );
1310 PanicIf ( !didItFit
, "AddNewRootNode:InsertKeyRecord failed for right index record");
1313 /////////////////////////// Release Root Node ///////////////////////////////
1315 err
= UpdateNode (btreePtr
, &rootNode
, 0, kLockTransaction
);
1316 M_ExitOnError (err
);
1318 // update BTreeInfoRec
1320 btreePtr
->rootNode
= rootNum
;
1321 btreePtr
->flags
|= kBTHeaderDirty
;
1326 ////////////////////////////// Error Exit ///////////////////////////////////
1334 static u_int16_t
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1338 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1339 length
= KeyLength (btreePtr
, key
); // just use actual key length
1341 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //\80\80 shouldn't we clear the pad bytes?