2 * Copyright (c) 1999-2000, 2002, 2007-2008 Apple Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 Contains: Multi-node tree operations for the BTree Module.
28 Version: xxx put the technology version here xxx
30 Written by: Gordon Sheridan and Bill Bruffey
32 Copyright: © 1992-1997, 1999 by Apple Computer, Inc., all rights reserved.
35 #include "BTreePrivate.h"
36 #include "../fsck_debug.h"
38 extern void plog(const char *fmt
, ...);
40 #define DEBUG_TREEOPS 0
42 /////////////////////// Routines Internal To BTree Module ///////////////////////
47 ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
49 static OSStatus
AddNewRootNode (BTreeControlBlockPtr btreePtr
,
51 NodeDescPtr rightNode
);
53 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
54 BlockDescriptor
*blockPtr
);
56 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
58 NodeDescPtr rightNode
,
59 UInt16 rightInsertIndex
,
64 UInt32
*insertNodeNum
,
66 UInt16
*recsRotated
);
68 static Boolean
RotateRecordLeft (BTreeControlBlockPtr btreePtr
,
70 NodeDescPtr rightNode
);
73 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
74 BlockDescriptor
*leftNode
,
75 BlockDescriptor
*rightNode
,
82 UInt32
*insertNodeNum
,
83 UInt16
*recsRotated
);
87 static OSStatus
InsertLevel (BTreeControlBlockPtr btreePtr
,
88 TreePathTable treePathTable
,
89 InsertKey
*primaryKey
,
90 InsertKey
*secondaryKey
,
91 BlockDescriptor
*targetNode
,
96 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
98 BlockDescriptor
*targetNode
,
103 BlockDescriptor
*leftNode
,
104 Boolean
*updateParent
,
105 Boolean
*insertParent
,
106 Boolean
*rootSplit
);
108 static UInt16
GetKeyLength (const BTreeControlBlock
*btreePtr
,
110 Boolean forLeafNode
);
112 static Boolean
RotateRecordRight( BTreeControlBlockPtr btreePtr
,
113 NodeDescPtr leftNode
,
114 NodeDescPtr rightNode
);
116 static OSStatus
RotateRight( BTreeControlBlockPtr btreePtr
,
117 NodeDescPtr leftNode
,
118 NodeDescPtr rightNode
,
119 UInt16 leftInsertIndex
,
124 UInt32
*insertNodeNum
,
126 UInt16
*recsRotated
);
128 static OSStatus
SplitRight( BTreeControlBlockPtr btreePtr
,
129 BlockDescriptor
*nodePtr
,
130 BlockDescriptor
*rightNodePtr
,
136 UInt16
*insertIndexPtr
,
137 UInt32
*newNodeNumPtr
,
138 UInt16
*recsRotatedPtr
);
141 static int DoKeyCheck( NodeDescPtr nodeP
, BTreeControlBlock
*btcb
);
142 static int DoKeyCheckAcrossNodes( NodeDescPtr theLeftNodePtr
,
143 NodeDescPtr theRightNodePtr
,
144 BTreeControlBlock
*theTreePtr
,
146 static void PrintNodeDescriptor( NodeDescPtr thePtr
);
147 static void PrintKey( UInt8
* myPtr
, int mySize
);
148 #endif // DEBUG_TREEOPS
151 /* used by InsertLevel (and called routines) to communicate the state of an insert operation */
154 kInsertParent
= 0x0001,
155 kUpdateParent
= 0x0002,
157 kInsertedInRight
= 0x0008,
162 //////////////////////// BTree Multi-node Tree Operations ///////////////////////
165 /*-------------------------------------------------------------------------------
167 Routine: SearchTree - Search BTree for key and set up Tree Path Table.
169 Function: Searches BTree for specified key, setting up the Tree Path Table to
170 reflect the search path.
173 Input: btreePtr - pointer to control block of BTree to search
174 keyPtr - pointer to the key to search for
175 treePathTable - pointer to the tree path table to construct
177 Output: nodeNum - number of the node containing the key position
178 iterator - BTreeIterator specifying record or insert position
180 Result: noErr - key found, index is record index
181 fsBTRecordNotFoundErr - key not found, index is insert index
182 fsBTEmptyErr - key not found, return params are nil
183 otherwise - catastrophic failure (GetNode/ReleaseNode failed)
184 -------------------------------------------------------------------------------*/
186 OSStatus
SearchTree (BTreeControlBlockPtr btreePtr
,
187 BTreeKeyPtr searchKey
,
188 TreePathTable treePathTable
,
190 BlockDescriptor
*nodePtr
,
191 UInt16
*returnIndex
)
199 SInt8 nodeKind
; // Kind of current node (index/leaf)
205 curNodeNum
= btreePtr
->rootNode
;
206 level
= btreePtr
->treeDepth
;
208 if (level
== 0) // is the tree empty?
214 //¥¥ for debugging...
215 treePathTable
[0].node
= 0;
216 treePathTable
[0].index
= 0;
221 // [2550929] Node number 0 is the header node. It is never a valid
222 // index or leaf node. If we're ever asked to search through node 0,
223 // something has gone wrong (typically a bad child node number, or
224 // we found a node full of zeroes that we thought was an index node).
228 // Panic("\pSearchTree: curNodeNum is zero!");
229 if (debug
) fprintf(stderr
, "%s(%d): curNodeNum is 0\n", __FUNCTION__
, __LINE__
);
230 err
= fsBTInvalidNodeErr
;
234 err
= GetNode (btreePtr
, curNodeNum
, &nodeRec
);
241 // [2550929] Sanity check the node height and node type. We expect
242 // particular values at each iteration in the search. This checking
243 // quickly finds bad pointers, loops, and other damage to the
244 // hierarchy of the B-tree.
246 if (((BTNodeDescriptor
*)nodeRec
.buffer
)->height
!= level
)
250 fprintf(stderr
, "%s(line %d): height %d != level %d\n", __FUNCTION__
, __LINE__
, ((BTNodeDescriptor
*)nodeRec
.buffer
)->height
, level
);
251 fprintf(stderr
, " curNodeNum = %u\n", curNodeNum
);
252 if (cur_debug_level
& d_dump_node
)
254 HexDump(nodeRec
.buffer
, nodeRec
.blockSize
, true);
257 err
= fsBTInvalidNodeErr
;
260 nodeKind
= ((BTNodeDescriptor
*)nodeRec
.buffer
)->kind
;
263 // Nodes at level 1 must be leaves, by definition
264 if (nodeKind
!= kBTLeafNode
)
266 if (debug
) fprintf(stderr
, "%s(%d): wrong kind of node\n", __FUNCTION__
, __LINE__
);
267 err
= fsBTInvalidNodeErr
;
273 // A node at any other depth must be an index node
274 if (nodeKind
!= kBTIndexNode
)
276 if (debug
) fprintf(stderr
, "%s(%d): other wrong kind of node\n", __FUNCTION__
, __LINE__
);
277 err
= fsBTInvalidNodeErr
;
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 siblingNode
;
392 UInt32 targetNodeNum
;
395 Boolean insertParent
;
396 Boolean updateParent
;
399 #if defined(applec) && !defined(__SC__)
400 PanicIf ((level
== 1) && (((NodeDescPtr
)targetNode
->buffer
)->kind
!= kBTLeafNode
), "\P InsertLevel: non-leaf at level 1! ");
402 siblingNode
.buffer
= nil
;
403 targetNodeNum
= treePathTable
[level
].node
;
405 insertParent
= false;
406 updateParent
= false;
408 ////// process first insert //////
410 err
= InsertNode (btreePtr
, primaryKey
, targetNode
, targetNodeNum
, index
,
411 &newNodeNum
, &newIndex
, &siblingNode
, &updateParent
, &insertParent
, &newRoot
);
416 // Extend the treePathTable by adding an entry for the new
417 // root node that references the current targetNode.
419 // When we split right the index in the new root is 0 if the new
420 // node is the same as the target node or 1 otherwise. When the
421 // new node number and the target node number are the same then
422 // we inserted the new record into the left node (the orignial target)
425 treePathTable
[level
+ 1].node
= btreePtr
->rootNode
;
426 if ( targetNodeNum
== newNodeNum
)
427 treePathTable
[level
+ 1].index
= 0; //
429 treePathTable
[level
+ 1].index
= 1;
433 *insertNode
= newNodeNum
;
435 ////// process second insert (if any) //////
437 if ( secondaryKey
!= nil
)
441 // NOTE - we only get here if we have split a child node to the right and
442 // we are currently updating the child's parent. newIndex + 1 refers to
443 // the location in the parent node where we insert the new index record that
444 // represents the new child node (the new right node).
445 err
= InsertNode (btreePtr
, secondaryKey
, targetNode
, newNodeNum
, newIndex
+ 1,
446 &newNodeNum
, &newIndex
, &siblingNode
, &updateParent
, &insertParent
, &temp
);
449 if ( DEBUG_BUILD
&& updateParent
&& newRoot
)
450 DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
453 //////////////////////// Update Parent(s) ///////////////////////////////
455 if ( insertParent
|| updateParent
)
457 BlockDescriptor parentNode
;
458 UInt32 parentNodeNum
;
465 PanicIf ( (level
== btreePtr
->treeDepth
), "\p InsertLevel: unfinished insert!?");
469 // Get Parent Node data...
470 index
= treePathTable
[level
].index
;
471 parentNodeNum
= treePathTable
[level
].node
;
473 PanicIf ( parentNodeNum
== 0, "\p InsertLevel: parent node is zero!?");
475 err
= GetNode (btreePtr
, parentNodeNum
, &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
, "\P InsertLevel: parent node not an index node! ");
481 ////////////////////////// Update Parent Index //////////////////////////////
485 //¥¥Êdebug: check if ptr == targetNodeNum
486 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
487 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p InsertLevel: parent ptr doesn't match target node!");
489 // need to delete and re-insert this parent key/ptr
490 // we delete it here and it gets re-inserted in the
491 // InsertLevel call below.
492 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
494 primaryKey
->keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
495 primaryKey
->keyLength
= GetKeyLength(btreePtr
, primaryKey
->keyPtr
, false);
496 primaryKey
->recPtr
= (UInt8
*) &targetNodeNum
;
497 primaryKey
->recSize
= sizeof(targetNodeNum
);
498 primaryKey
->replacingKey
= kReplaceRecord
;
499 primaryKey
->skipRotate
= insertParent
; // don't rotate left if we have two inserts occuring
502 ////////////////////////// Add New Parent Index /////////////////////////////
506 InsertKey
*insertKeyPtr
;
511 insertKeyPtr
= &insertKey
;
512 secondaryKey
= &insertKey
;
516 insertKeyPtr
= primaryKey
;
517 // split right but not updating parent for our left node then
518 // we want to insert the key for the new right node just after
519 // the key for our left node.
523 insertKeyPtr
->keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, siblingNode
.buffer
, 0);
524 insertKeyPtr
->keyLength
= GetKeyLength(btreePtr
, insertKeyPtr
->keyPtr
, false);
525 insertKeyPtr
->recPtr
= (UInt8
*) &((NodeDescPtr
)targetNode
->buffer
)->fLink
;
526 insertKeyPtr
->recSize
= sizeof(UInt32
);
527 insertKeyPtr
->replacingKey
= kInsertRecord
;
528 insertKeyPtr
->skipRotate
= false; // a rotate is OK during second insert
531 err
= InsertLevel (btreePtr
, treePathTable
, primaryKey
, secondaryKey
,
532 &parentNode
, index
, level
, insertNode
);
536 err
= UpdateNode (btreePtr
, targetNode
); // all done with target
539 err
= UpdateNode (btreePtr
, &siblingNode
); // all done with left sibling
546 (void) ReleaseNode (btreePtr
, targetNode
);
547 (void) ReleaseNode (btreePtr
, &siblingNode
);
549 Panic ("\p InsertLevel: an error occured!");
553 } // End of InsertLevel
557 ////////////////////////////////// InsertNode ///////////////////////////////////
559 static OSErr
InsertNode (BTreeControlBlockPtr btreePtr
,
562 BlockDescriptor
*targetNode
,
566 UInt32
*newNodeNumPtr
,
569 BlockDescriptor
*siblingNode
,
570 Boolean
*updateParent
,
571 Boolean
*insertParent
,
574 BlockDescriptor
*tempNode
;
583 PanicIf ( targetNode
->buffer
== siblingNode
->buffer
, "\p InsertNode: targetNode == siblingNode, huh?");
585 leftNodeNum
= ((NodeDescPtr
) targetNode
->buffer
)->bLink
;
586 rightNodeNum
= ((NodeDescPtr
) targetNode
->buffer
)->fLink
;
589 /////////////////////// Try Simple Insert ///////////////////////////////
591 if ( nodeNum
== leftNodeNum
)
592 tempNode
= siblingNode
;
594 tempNode
= targetNode
;
596 recordFit
= InsertKeyRecord (btreePtr
, tempNode
->buffer
, index
, key
->keyPtr
, key
->keyLength
, key
->recPtr
, key
->recSize
);
600 *newNodeNumPtr
= nodeNum
;
604 if ( DoKeyCheck( tempNode
->buffer
, btreePtr
) != noErr
)
606 plog( "\n%s - bad key order in node num %d: \n", __FUNCTION__
, nodeNum
);
607 PrintNodeDescriptor( tempNode
->buffer
);
608 err
= fsBTBadRotateErr
;
611 #endif // DEBUG_TREEOPS
613 if ( (index
== 0) && (((NodeDescPtr
) tempNode
->buffer
)->height
!= btreePtr
->treeDepth
) )
614 *updateParent
= true; // the first record changed so we need to update the parent
615 goto ExitThisRoutine
;
619 //////////////////////// Try Rotate Left ////////////////////////////////
621 if ( leftNodeNum
> 0 )
623 PanicIf ( siblingNode
->buffer
!= nil
, "\p InsertNode: siblingNode already aquired!");
625 if ( siblingNode
->buffer
== nil
)
627 err
= GetNode (btreePtr
, leftNodeNum
, siblingNode
); // will be released by caller or a split below
631 PanicIf ( ((NodeDescPtr
) siblingNode
->buffer
)->fLink
!= nodeNum
, "\p InsertNode, RotateLeft: invalid sibling link!" );
633 if ( !key
->skipRotate
) // are rotates allowed?
635 err
= RotateLeft (btreePtr
, siblingNode
->buffer
, targetNode
->buffer
, index
, key
->keyPtr
, key
->recPtr
,
636 key
->recSize
, newIndex
, newNodeNumPtr
, &recordFit
, &recsRotated
);
641 if ( key
->replacingKey
|| (recsRotated
> 1) || (index
> 0) )
642 *updateParent
= true;
643 goto ExitThisRoutine
;
649 //////////////////////// Try Split Right /////////////////////////////////
651 (void) ReleaseNode( btreePtr
, siblingNode
);
652 err
= SplitRight( btreePtr
, targetNode
, siblingNode
, nodeNum
, index
, key
->keyPtr
,
653 key
->recPtr
, key
->recSize
, newIndex
, newNodeNumPtr
, &recsRotated
);
656 // if we split root node - add new root
657 if ( ((NodeDescPtr
) targetNode
->buffer
)->height
== btreePtr
->treeDepth
)
659 err
= AddNewRootNode( btreePtr
, targetNode
->buffer
, siblingNode
->buffer
); // Note: does not update TPT
665 *insertParent
= true;
667 // update parent index node when replacingKey is true or when
668 // we inserted a new record at the beginning of our target node.
669 if ( key
->replacingKey
|| ( index
== 0 && *newIndex
== 0 ) )
670 *updateParent
= true;
679 (void) ReleaseNode (btreePtr
, siblingNode
);
682 } // End of InsertNode
685 /*-------------------------------------------------------------------------------
686 Routine: DeleteTree - One_line_description.
688 Function: Brief_description_of_the_function_and_any_side_effects
692 Input: btreePtr - description
693 treePathTable - description
694 targetNode - description
697 Result: noErr - success
699 -------------------------------------------------------------------------------*/
701 OSStatus
DeleteTree (BTreeControlBlockPtr btreePtr
,
702 TreePathTable treePathTable
,
703 BlockDescriptor
*targetNode
,
708 BlockDescriptor parentNode
;
709 BTNodeDescriptor
*targetNodePtr
;
710 UInt32 targetNodeNum
;
711 Boolean deleteRequired
;
712 Boolean updateRequired
;
715 deleteRequired
= false;
716 updateRequired
= false;
718 targetNodeNum
= treePathTable
[level
].node
;
719 targetNodePtr
= targetNode
->buffer
;
720 PanicIf (targetNodePtr
== nil
, "\pDeleteTree: targetNode has nil buffer!");
722 DeleteRecord (btreePtr
, targetNodePtr
, index
);
724 //¥¥ coalesce remaining records?
726 if ( targetNodePtr
->numRecords
== 0 ) // did we delete the last record?
728 BlockDescriptor siblingNode
;
729 UInt32 siblingNodeNum
;
731 deleteRequired
= true;
733 ////////////////// Get Siblings & Update Links //////////////////////////
735 siblingNodeNum
= targetNodePtr
->bLink
; // Left Sibling Node
736 if ( siblingNodeNum
!= 0 )
738 err
= GetNode (btreePtr
, siblingNodeNum
, &siblingNode
);
740 ((NodeDescPtr
)siblingNode
.buffer
)->fLink
= targetNodePtr
->fLink
;
741 err
= UpdateNode (btreePtr
, &siblingNode
);
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
);
754 ((NodeDescPtr
)siblingNode
.buffer
)->bLink
= targetNodePtr
->bLink
;
755 err
= UpdateNode (btreePtr
, &siblingNode
);
758 else if ( targetNodePtr
->kind
== kBTLeafNode
) // update lastLeafNode
760 btreePtr
->lastLeafNode
= targetNodePtr
->bLink
;
763 //////////////////////// Free Empty Node ////////////////////////////////
765 ClearNode (btreePtr
, targetNodePtr
);
767 err
= UpdateNode (btreePtr
, targetNode
);
769 err
= FreeNode (btreePtr
, targetNodeNum
);
772 else if ( index
== 0 ) // did we delete the first record?
774 updateRequired
= true; // yes, so we need to update parent
778 if ( level
== btreePtr
->treeDepth
) // then targetNode->buffer is the root node
780 deleteRequired
= false;
781 updateRequired
= false;
783 if ( targetNode
->buffer
== nil
) // then root was freed and the btree is empty
785 btreePtr
->rootNode
= 0;
786 btreePtr
->treeDepth
= 0;
788 else if ( ((NodeDescPtr
)targetNode
->buffer
)->numRecords
== 1 )
790 err
= CollapseTree (btreePtr
, targetNode
);
796 if ( updateRequired
|| deleteRequired
)
798 ++level
; // next level
800 //// Get Parent Node and index
801 index
= treePathTable
[level
].index
;
802 err
= GetNode (btreePtr
, treePathTable
[level
].node
, &parentNode
);
805 if ( updateRequired
)
812 //¥¥Êdebug: check if ptr == targetNodeNum
813 GetRecordByIndex (btreePtr
, parentNode
.buffer
, index
, &keyPtr
, &recPtr
, &recSize
);
814 PanicIf( (*(UInt32
*) recPtr
) != targetNodeNum
, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
816 // need to delete and re-insert this parent key/ptr
817 DeleteRecord (btreePtr
, parentNode
.buffer
, index
);
819 keyPtr
= (KeyPtr
) GetRecordAddress( btreePtr
, targetNode
->buffer
, 0 );
820 recPtr
= (UInt8
*) &targetNodeNum
;
821 recSize
= sizeof(targetNodeNum
);
823 err
= InsertTree (btreePtr
, treePathTable
, keyPtr
, recPtr
, recSize
,
824 &parentNode
, index
, level
, kReplaceRecord
, &insertNode
);
827 else // deleteRequired
829 err
= DeleteTree (btreePtr
, treePathTable
, &parentNode
, index
, level
);
835 err
= UpdateNode (btreePtr
, targetNode
);
842 (void) ReleaseNode (btreePtr
, targetNode
);
843 (void) ReleaseNode (btreePtr
, &parentNode
);
851 ///////////////////////////////// CollapseTree //////////////////////////////////
853 static OSStatus
CollapseTree (BTreeControlBlockPtr btreePtr
,
854 BlockDescriptor
*blockPtr
)
860 originalRoot
= btreePtr
->rootNode
;
864 if ( ((NodeDescPtr
)blockPtr
->buffer
)->numRecords
> 1)
865 break; // this will make a fine root node
867 if ( ((NodeDescPtr
)blockPtr
->buffer
)->kind
== kBTLeafNode
)
868 break; // we've hit bottom
870 nodeNum
= btreePtr
->rootNode
;
871 btreePtr
->rootNode
= GetChildNodeNum (btreePtr
, blockPtr
->buffer
, 0);
872 --btreePtr
->treeDepth
;
874 //// Clear and Free Current Old Root Node ////
875 ClearNode (btreePtr
, blockPtr
->buffer
);
876 err
= UpdateNode (btreePtr
, blockPtr
);
878 err
= FreeNode (btreePtr
, nodeNum
);
881 //// Get New Root Node
882 err
= GetNode (btreePtr
, btreePtr
->rootNode
, blockPtr
);
886 if (btreePtr
->rootNode
!= originalRoot
)
887 M_BTreeHeaderDirty (btreePtr
);
889 err
= UpdateNode (btreePtr
, blockPtr
); // always update!
895 /////////////////////////////////// ErrorExit ///////////////////////////////////
898 (void) ReleaseNode (btreePtr
, blockPtr
);
904 ////////////////////////////////// RotateLeft ///////////////////////////////////
906 /*-------------------------------------------------------------------------------
908 Routine: RotateLeft - One_line_description.
910 Function: Brief_description_of_the_function_and_any_side_effects
912 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
914 Input: btreePtr - description
915 leftNode - description
916 rightNode - description
917 rightInsertIndex - description
920 recSize - description
923 insertNodeNum - description
924 recordFit - description
927 Result: noErr - success
929 -------------------------------------------------------------------------------*/
931 static OSStatus
RotateLeft (BTreeControlBlockPtr btreePtr
,
932 NodeDescPtr leftNode
,
933 NodeDescPtr rightNode
,
934 UInt16 rightInsertIndex
,
939 UInt32
*insertNodeNum
,
941 UInt16
*recsRotated
)
946 SInt32 leftSize
, rightSize
;
949 UInt16 lengthFieldSize
;
950 UInt16 index
, moveIndex
;
953 ///////////////////// Determine If Record Will Fit //////////////////////////
955 keyLength
= GetKeyLength(btreePtr
, keyPtr
, (rightNode
->kind
== kBTLeafNode
));
957 // the key's length field is 8-bits in HFS and 16-bits in HFS+
958 if ( btreePtr
->attributes
& kBTBigKeysMask
)
959 lengthFieldSize
= sizeof(UInt16
);
961 lengthFieldSize
= sizeof(UInt8
);
963 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
965 if ( M_IsOdd (insertSize
) )
966 ++insertSize
; // add pad byte;
968 nodeSize
= btreePtr
->nodeSize
;
970 // add size of insert record to right node
971 rightSize
= nodeSize
- GetNodeFreeSize (btreePtr
, rightNode
) + insertSize
;
972 leftSize
= nodeSize
- GetNodeFreeSize (btreePtr
, leftNode
);
977 while ( leftSize
< rightSize
)
979 if ( moveIndex
< rightInsertIndex
)
981 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
) + 2;
983 else if ( moveIndex
== rightInsertIndex
)
985 moveSize
= insertSize
;
987 else // ( moveIndex > rightInsertIndex )
989 moveSize
= GetRecordSize (btreePtr
, rightNode
, moveIndex
- 1) + 2;
992 leftSize
+= moveSize
;
993 rightSize
-= moveSize
;
997 if ( leftSize
> nodeSize
) // undo last move
999 leftSize
-= moveSize
;
1000 rightSize
+= moveSize
;
1004 if ( rightSize
> nodeSize
) // record won't fit - failure, but not error
1014 // we've found balance point, moveIndex == number of records moved into leftNode
1017 //////////////////////////// Rotate Records /////////////////////////////////
1019 *recsRotated
= moveIndex
;
1023 while ( index
< moveIndex
)
1025 if ( index
== rightInsertIndex
) // insert new record in left node
1027 UInt16 leftInsertIndex
;
1029 leftInsertIndex
= leftNode
->numRecords
;
1031 didItFit
= InsertKeyRecord (btreePtr
, leftNode
, leftInsertIndex
,
1032 keyPtr
, keyLength
, recPtr
, recSize
);
1035 Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
1036 err
= fsBTBadRotateErr
;
1040 *insertIndex
= leftInsertIndex
;
1041 *insertNodeNum
= rightNode
->bLink
;
1045 didItFit
= RotateRecordLeft (btreePtr
, leftNode
, rightNode
);
1048 Panic ("\pRotateLeft: RotateRecordLeft returned false!");
1049 err
= fsBTBadRotateErr
;
1057 if ( moveIndex
<= rightInsertIndex
) // then insert new record in right node
1059 rightInsertIndex
-= index
; // adjust for records already rotated
1061 didItFit
= InsertKeyRecord (btreePtr
, rightNode
, rightInsertIndex
,
1062 keyPtr
, keyLength
, recPtr
, recSize
);
1065 Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
1066 err
= fsBTBadRotateErr
;
1070 *insertIndex
= rightInsertIndex
;
1071 *insertNodeNum
= leftNode
->fLink
;
1075 if ( DoKeyCheck( leftNode
, btreePtr
) != noErr
)
1077 plog( "\n%s - bad key order in left node num %d: \n", __FUNCTION__
, rightNode
->bLink
);
1078 PrintNodeDescriptor( leftNode
);
1079 err
= fsBTBadRotateErr
;
1082 if ( DoKeyCheck( rightNode
, btreePtr
) != noErr
)
1084 plog( "\n%s - bad key order in left node num %d: \n", __FUNCTION__
, leftNode
->fLink
);
1085 PrintNodeDescriptor( rightNode
);
1086 err
= fsBTBadRotateErr
;
1089 #endif // DEBUG_TREEOPS
1095 ////////////////////////////// Error Exit ///////////////////////////////////
1109 /////////////////////////////////// SplitLeft ///////////////////////////////////
1111 static OSStatus
SplitLeft (BTreeControlBlockPtr btreePtr
,
1112 BlockDescriptor
*leftNode
,
1113 BlockDescriptor
*rightNode
,
1114 UInt32 rightNodeNum
,
1119 UInt16
*insertIndex
,
1120 UInt32
*insertNodeNum
,
1121 UInt16
*recsRotated
)
1124 NodeDescPtr left
, right
;
1129 ///////////////////////////// Compare Nodes /////////////////////////////////
1131 right
= rightNode
->buffer
;
1132 left
= leftNode
->buffer
;
1134 PanicIf ( right
->bLink
!= 0 && left
== 0, "\p SplitLeft: left sibling missing!?" );
1136 //¥¥ type should be kLeafNode or kIndexNode
1138 if ( (right
->height
== 1) && (right
->kind
!= kBTLeafNode
) )
1139 return fsBTInvalidNodeErr
;
1143 if ( left
->fLink
!= rightNodeNum
)
1144 return fsBTInvalidNodeErr
; //¥¥ E_BadSibling ?
1146 if ( left
->height
!= right
->height
)
1147 return fsBTInvalidNodeErr
; //¥¥ E_BadNodeHeight ?
1149 if ( left
->kind
!= right
->kind
)
1150 return fsBTInvalidNodeErr
; //¥¥ E_BadNodeType ?
1154 ///////////////////////////// Allocate Node /////////////////////////////////
1156 err
= AllocateNode (btreePtr
, &newNodeNum
);
1157 M_ExitOnError (err
);
1160 /////////////// Update Forward Link In Original Left Node ///////////////////
1164 left
->fLink
= newNodeNum
;
1165 err
= UpdateNode (btreePtr
, leftNode
);
1166 M_ExitOnError (err
);
1170 /////////////////////// Initialize New Left Node ////////////////////////////
1172 err
= GetNewNode (btreePtr
, newNodeNum
, leftNode
);
1173 M_ExitOnError (err
);
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
); //¥¥ 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
);
1199 M_ExitOnError (err
);
1205 (void) ReleaseNode (btreePtr
, leftNode
);
1206 (void) ReleaseNode (btreePtr
, rightNode
);
1208 //¥¥ 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 PanicIf (leftNode
== nil
, "\pAddNewRootNode: leftNode == nil");
1258 PanicIf (rightNode
== nil
, "\pAddNewRootNode: rightNode == nil");
1261 /////////////////////// Initialize New Root Node ////////////////////////////
1263 err
= AllocateNode (btreePtr
, &rootNum
);
1264 M_ExitOnError (err
);
1266 err
= GetNewNode (btreePtr
, rootNum
, &rootNode
);
1267 M_ExitOnError (err
);
1269 ((NodeDescPtr
)rootNode
.buffer
)->kind
= kBTIndexNode
;
1270 ((NodeDescPtr
)rootNode
.buffer
)->height
= ++btreePtr
->treeDepth
;
1273 ///////////////////// Insert Left Node Index Record /////////////////////////
1275 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, leftNode
, 0);
1276 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1278 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 0, keyPtr
, keyLength
,
1279 (UInt8
*) &rightNode
->bLink
, 4 );
1281 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1284 //////////////////// Insert Right Node Index Record /////////////////////////
1286 keyPtr
= (KeyPtr
) GetRecordAddress (btreePtr
, rightNode
, 0);
1287 keyLength
= GetKeyLength(btreePtr
, keyPtr
, false);
1289 didItFit
= InsertKeyRecord ( btreePtr
, rootNode
.buffer
, 1, keyPtr
, keyLength
,
1290 (UInt8
*) &leftNode
->fLink
, 4 );
1292 PanicIf ( !didItFit
, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1296 if ( DoKeyCheck( rootNode
.buffer
, btreePtr
) != noErr
)
1298 plog( "\n%s - bad key order in root node num %d: \n", __FUNCTION__
, rootNum
);
1299 PrintNodeDescriptor( rootNode
.buffer
);
1300 err
= fsBTBadRotateErr
;
1303 #endif // DEBUG_TREEOPS
1306 /////////////////////////// Release Root Node ///////////////////////////////
1308 err
= UpdateNode (btreePtr
, &rootNode
);
1309 M_ExitOnError (err
);
1311 // update BTreeInfoRec
1313 btreePtr
->rootNode
= rootNum
;
1314 btreePtr
->flags
|= kBTHeaderDirty
;
1319 ////////////////////////////// Error Exit ///////////////////////////////////
1327 static UInt16
GetKeyLength ( const BTreeControlBlock
*btreePtr
, const BTreeKey
*key
, Boolean forLeafNode
)
1331 if ( forLeafNode
|| btreePtr
->attributes
& kBTVariableIndexKeysMask
)
1332 length
= KeyLength (btreePtr
, key
); // just use actual key length
1334 length
= btreePtr
->maxKeyLength
; // fixed sized index key (i.e. HFS) //¥¥ shouldn't we clear the pad bytes?
1341 /////////////////////////////////// SplitRight ///////////////////////////////////
1343 static OSStatus
SplitRight (BTreeControlBlockPtr btreePtr
,
1344 BlockDescriptor
*nodePtr
,
1345 BlockDescriptor
*rightNodePtr
,
1351 UInt16
*insertIndexPtr
,
1352 UInt32
*newNodeNumPtr
,
1353 UInt16
*recsRotatedPtr
)
1356 NodeDescPtr leftPtr
, rightPtr
;
1361 ///////////////////////////// Compare Nodes /////////////////////////////////
1363 leftPtr
= nodePtr
->buffer
;
1365 if ( leftPtr
->fLink
!= 0 )
1367 err
= GetNode( btreePtr
, leftPtr
->fLink
, rightNodePtr
);
1368 M_ExitOnError( err
);
1370 rightPtr
= rightNodePtr
->buffer
;
1372 PanicIf ( leftPtr
->fLink
!= 0 && rightPtr
== 0, "\p SplitRight: right sibling missing!?" );
1374 //¥¥ type should be kLeafNode or kIndexNode
1376 if ( (leftPtr
->height
== 1) && (leftPtr
->kind
!= kBTLeafNode
) )
1377 return fsBTInvalidNodeErr
;
1379 if ( rightPtr
!= nil
)
1381 if ( rightPtr
->bLink
!= nodeNum
)
1382 return fsBTInvalidNodeErr
; //¥¥ E_BadSibling ?
1384 if ( rightPtr
->height
!= leftPtr
->height
)
1385 return fsBTInvalidNodeErr
; //¥¥ E_BadNodeHeight ?
1387 if ( rightPtr
->kind
!= leftPtr
->kind
)
1388 return fsBTInvalidNodeErr
; //¥¥ E_BadNodeType ?
1392 ///////////////////////////// Allocate Node /////////////////////////////////
1394 err
= AllocateNode (btreePtr
, &newNodeNum
);
1395 M_ExitOnError (err
);
1397 /////////////// Update backward Link In Original Right Node ///////////////////
1399 if ( rightPtr
!= nil
)
1401 rightPtr
->bLink
= newNodeNum
;
1402 err
= UpdateNode (btreePtr
, rightNodePtr
);
1403 M_ExitOnError (err
);
1406 /////////////////////// Initialize New Right Node ////////////////////////////
1408 err
= GetNewNode (btreePtr
, newNodeNum
, rightNodePtr
);
1409 M_ExitOnError (err
);
1411 rightPtr
= rightNodePtr
->buffer
;
1412 rightPtr
->bLink
= nodeNum
;
1415 // Steal Info From Left Node
1417 rightPtr
->fLink
= leftPtr
->fLink
;
1418 rightPtr
->kind
= leftPtr
->kind
;
1419 rightPtr
->height
= leftPtr
->height
;
1421 leftPtr
->fLink
= newNodeNum
; // update Left fLink
1423 if ( (rightPtr
->kind
== kBTLeafNode
) && (rightPtr
->fLink
== 0) )
1425 // if we're adding a new last leaf node - update BTreeInfoRec
1427 btreePtr
->lastLeafNode
= newNodeNum
;
1428 M_BTreeHeaderDirty (btreePtr
); //¥¥ AllocateNode should have set the bit already...
1431 ////////////////////////////// Rotate Right //////////////////////////////////
1433 err
= RotateRight (btreePtr
, leftPtr
, rightPtr
, index
, keyPtr
, recPtr
, recSize
,
1434 insertIndexPtr
, newNodeNumPtr
, &recordFit
, recsRotatedPtr
);
1435 M_ExitOnError (err
);
1441 (void) ReleaseNode (btreePtr
, nodePtr
);
1442 (void) ReleaseNode (btreePtr
, rightNodePtr
);
1444 //¥¥ Free new node if allocated?
1446 *insertIndexPtr
= 0;
1448 *recsRotatedPtr
= 0;
1456 ////////////////////////////////// RotateRight ///////////////////////////////////
1458 /*-------------------------------------------------------------------------------
1460 Routine: RotateRight - rotate half of .
1462 Function: Brief_description_of_the_function_and_any_side_effects
1464 Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
1466 Input: btreePtr - description
1467 leftNode - description
1468 rightNode - description
1469 leftInsertIndex - description
1470 keyPtr - description
1471 recPtr - description
1472 recSize - description
1475 insertNodeNum - description
1476 recordFit - description
1479 Result: noErr - success
1481 -------------------------------------------------------------------------------*/
1483 static OSStatus
RotateRight (BTreeControlBlockPtr btreePtr
,
1484 NodeDescPtr leftNodePtr
,
1485 NodeDescPtr rightNodePtr
,
1486 UInt16 leftInsertIndex
,
1490 UInt16
*insertIndexPtr
,
1491 UInt32
*newNodeNumPtr
,
1492 Boolean
*didRecordFitPtr
,
1493 UInt16
*recsRotatedPtr
)
1498 SInt32 leftSize
, rightSize
;
1501 UInt16 lengthFieldSize
;
1502 SInt16 index
, moveIndex
, myInsertIndex
;
1504 Boolean doIncrement
= false;
1506 ///////////////////// Determine If Record Will Fit //////////////////////////
1508 keyLength
= GetKeyLength( btreePtr
, keyPtr
, (leftNodePtr
->kind
== kBTLeafNode
) );
1510 // the key's length field is 8-bits in HFS and 16-bits in HFS+
1511 if ( btreePtr
->attributes
& kBTBigKeysMask
)
1512 lengthFieldSize
= sizeof(UInt16
);
1514 lengthFieldSize
= sizeof(UInt8
);
1517 * A record size in a node is the size of the key, the size of the key length field,
1518 * the size of the record, and the size of the record offset index.
1520 insertSize
= keyLength
+ lengthFieldSize
+ recSize
+ sizeof(UInt16
);
1521 if ( M_IsOdd (insertSize
) )
1522 ++insertSize
; // add pad byte;
1523 nodeSize
= btreePtr
->nodeSize
;
1525 // add size of insert record to left node
1526 rightSize
= nodeSize
- GetNodeFreeSize( btreePtr
, rightNodePtr
);
1527 leftSize
= nodeSize
- GetNodeFreeSize( btreePtr
, leftNodePtr
) + insertSize
;
1529 moveIndex
= leftNodePtr
->numRecords
; // start at last record in the node
1533 * The goal here is to attempt to make the nodes as balanced as
1534 * possible. We do this by "moving" records from the left node to
1535 * the right node, until the right node is larger than the left
1538 * We also need to factor in the new record for this; what we are
1539 * trying to do, as a result, is consider a virtual node that has
1540 * all of the old records in it, plus the new record inserted at
1541 * the proper place. (This is the reason for the if cases in the
1544 while ( rightSize
< leftSize
)
1547 * We set moveSize to the size of the record being moved in this
1548 * pass. We need to add sizeof(UInt16) because we need to account
1549 * for the record offset index, which is two bytes. This was already
1550 * added to insertSize above.
1552 if (moveIndex
> leftInsertIndex
)
1553 moveSize
= GetRecordSize( btreePtr
, leftNodePtr
, moveIndex
- 1) + sizeof(UInt16
);
1554 else if (moveIndex
== leftInsertIndex
)
1555 moveSize
= insertSize
;
1556 else // (moveIndex < leftInsertIndex)
1557 moveSize
= GetRecordSize( btreePtr
, leftNodePtr
, moveIndex
) + sizeof(UInt16
);
1559 leftSize
-= moveSize
;
1560 rightSize
+= moveSize
;
1564 if ( rightSize
> nodeSize
) // undo last move
1566 leftSize
+= moveSize
;
1567 rightSize
-= moveSize
;
1571 if ( leftSize
> nodeSize
) // record won't fit - failure, but not error
1573 *insertIndexPtr
= 0;
1575 *didRecordFitPtr
= false;
1576 *recsRotatedPtr
= 0;
1581 // we've found balance point, we rotate up to moveIndex into right node
1583 //////////////////////////// Rotate Records /////////////////////////////////
1585 *didRecordFitPtr
= true;
1586 index
= leftNodePtr
->numRecords
;
1587 *recsRotatedPtr
= index
- moveIndex
;
1590 // handle case where the new record is inserting after the last
1591 // record in our left node.
1592 if ( leftNodePtr
->numRecords
== leftInsertIndex
)
1594 didItFit
= InsertKeyRecord (btreePtr
, rightNodePtr
, 0,
1595 keyPtr
, keyLength
, recPtr
, recSize
);
1598 if (debug
) plog ("RotateRight: InsertKeyRecord (left) returned false!\n");
1599 err
= fsBTBadRotateErr
;
1603 // NOTE - our insert location will slide as we insert more records
1605 *newNodeNumPtr
= leftNodePtr
->fLink
;
1609 while ( index
> moveIndex
)
1611 if ( index
== leftInsertIndex
) // insert new record in right node
1613 didItFit
= InsertKeyRecord (btreePtr
, rightNodePtr
, 0,
1614 keyPtr
, keyLength
, recPtr
, recSize
);
1617 if (debug
) plog ("RotateRight: InsertKeyRecord (right) returned false!\n");
1618 err
= fsBTBadRotateErr
;
1622 // NOTE - our insert index will slide as we insert more records
1625 *newNodeNumPtr
= leftNodePtr
->fLink
;
1629 didItFit
= RotateRecordRight( btreePtr
, leftNodePtr
, rightNodePtr
);
1632 if (debug
) plog ("RotateRight: RotateRecordRight returned false!\n");
1633 err
= fsBTBadRotateErr
;
1643 *insertIndexPtr
= myInsertIndex
;
1645 if ( moveIndex
>= leftInsertIndex
) // then insert new record in left node
1647 didItFit
= InsertKeyRecord (btreePtr
, leftNodePtr
, leftInsertIndex
,
1648 keyPtr
, keyLength
, recPtr
, recSize
);
1651 if (debug
) plog ("RotateRight: InsertKeyRecord (left) returned false!\n");
1652 err
= fsBTBadRotateErr
;
1656 *insertIndexPtr
= leftInsertIndex
;
1657 *newNodeNumPtr
= rightNodePtr
->bLink
;
1661 if ( DoKeyCheck( rightNodePtr
, btreePtr
) != noErr
)
1663 plog( "\n%s - bad key order in right node num %d: \n", __FUNCTION__
, leftNodePtr
->fLink
);
1664 PrintNodeDescriptor( rightNodePtr
);
1665 err
= fsBTBadRotateErr
;
1668 if ( DoKeyCheck( leftNodePtr
, btreePtr
) != noErr
)
1670 plog( "\n%s - bad key order in left node num %d: \n", __FUNCTION__
, rightNodePtr
->bLink
);
1671 PrintNodeDescriptor( leftNodePtr
);
1672 err
= fsBTBadRotateErr
;
1675 if ( DoKeyCheckAcrossNodes( leftNodePtr
, rightNodePtr
, btreePtr
, false ) != noErr
)
1677 plog( "\n%s - bad key order across nodes left %d right %d: \n",
1678 __FUNCTION__
, rightNodePtr
->bLink
, leftNodePtr
->fLink
);
1679 PrintNodeDescriptor( leftNodePtr
);
1680 PrintNodeDescriptor( rightNodePtr
);
1681 err
= fsBTBadRotateErr
;
1684 #endif // DEBUG_TREEOPS
1689 ////////////////////////////// Error Exit ///////////////////////////////////
1693 *insertIndexPtr
= 0;
1695 *didRecordFitPtr
= false;
1696 *recsRotatedPtr
= 0;
1704 /////////////////////////////// RotateRecordRight ////////////////////////////////
1706 static Boolean
RotateRecordRight (BTreeControlBlockPtr btreePtr
,
1707 NodeDescPtr leftNodePtr
,
1708 NodeDescPtr rightNodePtr
)
1712 Boolean didRecordFit
;
1714 size
= GetRecordSize( btreePtr
, leftNodePtr
, leftNodePtr
->numRecords
- 1 ) ;
1715 recPtr
= GetRecordAddress( btreePtr
, leftNodePtr
, leftNodePtr
->numRecords
- 1 ) ;
1717 didRecordFit
= InsertRecord( btreePtr
, rightNodePtr
, 0, recPtr
, size
);
1718 if ( !didRecordFit
)
1721 DeleteRecord( btreePtr
, leftNodePtr
, leftNodePtr
->numRecords
- 1 );
1725 } /* RotateRecordRight */
1730 static int DoKeyCheckAcrossNodes( NodeDescPtr theLeftNodePtr
,
1731 NodeDescPtr theRightNodePtr
,
1732 BTreeControlBlock
*theTreePtr
,
1735 UInt16 myLeftDataSize
;
1736 UInt16 myRightDataSize
;
1737 UInt16 myRightKeyLen
;
1738 UInt16 myLeftKeyLen
;
1739 KeyPtr myLeftKeyPtr
;
1740 KeyPtr myRightKeyPtr
;
1741 UInt8
* myLeftDataPtr
;
1742 UInt8
* myRightDataPtr
;
1745 GetRecordByIndex( theTreePtr
, theLeftNodePtr
, (theLeftNodePtr
->numRecords
- 1),
1746 &myLeftKeyPtr
, &myLeftDataPtr
, &myLeftDataSize
);
1747 GetRecordByIndex( theTreePtr
, theRightNodePtr
, 0,
1748 &myRightKeyPtr
, &myRightDataPtr
, &myRightDataSize
);
1750 if ( theTreePtr
->attributes
& kBTBigKeysMask
)
1752 myRightKeyLen
= myRightKeyPtr
->length16
;
1753 myLeftKeyLen
= myLeftKeyPtr
->length16
;
1757 myRightKeyLen
= myRightKeyPtr
->length8
;
1758 myLeftKeyLen
= myLeftKeyPtr
->length8
;
1763 plog( "%s - left and right keys:\n", __FUNCTION__
);
1764 PrintKey( (UInt8
*) myLeftKeyPtr
, myLeftKeyLen
);
1765 PrintKey( (UInt8
*) myRightKeyPtr
, myRightKeyLen
);
1768 if ( CompareKeys( theTreePtr
, myLeftKeyPtr
, myRightKeyPtr
) >= 0 )
1773 } /* DoKeyCheckAcrossNodes */
1776 static int DoKeyCheck( NodeDescPtr nodeP
, BTreeControlBlock
*btcb
)
1783 KeyPtr prevkeyP
= nil
;
1786 if ( nodeP
->numRecords
== 0 )
1788 if ( (nodeP
->fLink
== 0) && (nodeP
->bLink
== 0) )
1794 * Loop on number of records in node
1796 for ( index
= 0; index
< nodeP
->numRecords
; index
++)
1798 GetRecordByIndex( (BTreeControlBlock
*)btcb
, nodeP
, (UInt16
) index
, &keyPtr
, &dataPtr
, &dataSize
);
1800 if (btcb
->attributes
& kBTBigKeysMask
)
1801 keyLength
= keyPtr
->length16
;
1803 keyLength
= keyPtr
->length8
;
1805 if ( keyLength
> btcb
->maxKeyLength
)
1810 if ( prevkeyP
!= nil
)
1812 if ( CompareKeys( (BTreeControlBlockPtr
)btcb
, prevkeyP
, keyPtr
) >= 0 )
1825 static void PrintNodeDescriptor( NodeDescPtr thePtr
)
1827 plog( " fLink %d bLink %d kind %d height %d numRecords %d \n",
1828 thePtr
->fLink
, thePtr
->bLink
, thePtr
->kind
, thePtr
->height
, thePtr
->numRecords
);
1832 static void PrintKey( UInt8
* myPtr
, int mySize
)
1836 for ( i
= 0; i
< mySize
+2; i
++ )
1838 plog("%02X", *(myPtr
+ i
) );
1844 #endif // DEBUG_TREEOPS