|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: File: BTreeTreeOps.c
24:
25: Contains: Multi-node tree operations for the BTree Module.
26:
27: Version: xxx put the technology version here xxx
28:
29: Written by: Gordon Sheridan and Bill Bruffey
30:
31: Copyright: � 1992-1999 by Apple Computer, Inc., all rights reserved.
32:
33: File Ownership:
34:
35: DRI: Don Brady
36:
37: Other Contact: Mark Day
38:
39: Technology: File Systems
40:
41: Writers:
42:
43: (msd) Mark Day
44: (DSH) Deric Horn
45: (djb) Don Brady
46:
47: Change History (most recent first):
48:
49: <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
50: <CS5> 12/8/97 djb Radar #2200632, CollapseTree wasn't marking root node dirty.
51: <CS4> 11/24/97 djb Radar #2005325, InsertLevel incorrectly handled root splits!
52: <CS3> 10/17/97 msd Conditionalize DebugStrs.
53: <CS2> 5/16/97 msd InsertNode() needs a return statement in ErrorExit.
54: <CS1> 4/23/97 djb first checked in
55:
56: <HFS8> 3/17/97 DSH Conditionalize out Panic assertion for SC.
57: <HFS7> 3/3/97 djb Removed DebugStr in InsertLevel.
58: <HFS6> 2/19/97 djb Major re-write of insert code; added InsertLevel and InsertNode.
59: <HFS5> 1/27/97 djb InsertTree and DeleteTree are now recursive and support variable
60: sized index keys.
61: <HFS4> 1/16/97 djb Removed DebugStr in SearchTree. Added initial support for
62: variable sized index keys.
63: <HFS3> 1/3/97 djb Changed len8 to length8.
64: <HFS2> 1/3/97 djb Added support for large keys.
65: <HFS1> 12/19/96 djb first checked in
66:
67: History applicable to original Scarecrow Design:
68:
69: <3> 10/25/96 ser Changing for new VFPI
70: <2> 1/22/96 dkh Add #include Memory.h
71: <1> 10/18/95 rst Moved from Scarecrow project.
72:
73: <12> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
74: <11> 9/30/94 prp Get in sync with D2 interface changes.
75: <10> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
76: <9> 7/22/94 wjk Convert to the new set of header files.
77: <8> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
78: NRCmds environments.
79: <7> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
80: agree with their prototypes.
81: <6> 5/21/93 gs Debug DeleteTree. Modify InsertTree for BTReplaceRecord.
82: <5> 5/10/93 gs Modify RotateLeft, and add DeleteTree, CollapseTree routines.
83: <4> 3/23/93 gs revise RotateLeft to use InsertKeyRecord instead of
84: InsertRecord.
85: <3> 3/23/93 gs Implement SplitLeft, InsertTree routine.
86: <2> 2/8/93 gs Implement SearchTree, and RotateLeft.
87: <1> 11/15/92 gs first checked in
88:
89: */
90:
91: #include "../headers/BTreesPrivate.h"
92:
93: //
94: /////////////////////// Routines Internal To BTree Module ///////////////////////
95: //
96: // SearchTree
97: // InsertTree
98: //
99: ////////////////////// Routines Internal To BTreeTreeOps.c //////////////////////
100:
101: static OSStatus AddNewRootNode (BTreeControlBlockPtr btreePtr,
102: NodeDescPtr leftNode,
103: NodeDescPtr rightNode );
104:
105: static OSStatus CollapseTree (BTreeControlBlockPtr btreePtr,
106: BlockDescriptor *blockPtr );
107:
108: static OSStatus RotateLeft (BTreeControlBlockPtr btreePtr,
109: NodeDescPtr leftNode,
110: NodeDescPtr rightNode,
111: UInt16 rightInsertIndex,
112: KeyPtr keyPtr,
113: UInt8 * recPtr,
114: UInt16 recSize,
115: UInt16 *insertIndex,
116: UInt32 *insertNodeNum,
117: Boolean *recordFit,
118: UInt16 *recsRotated );
119:
120: static Boolean RotateRecordLeft (BTreeControlBlockPtr btreePtr,
121: NodeDescPtr leftNode,
122: NodeDescPtr rightNode );
123:
124: static OSStatus SplitLeft (BTreeControlBlockPtr btreePtr,
125: BlockDescriptor *leftNode,
126: BlockDescriptor *rightNode,
127: UInt32 rightNodeNum,
128: UInt16 index,
129: KeyPtr keyPtr,
130: UInt8 * recPtr,
131: UInt16 recSize,
132: UInt16 *insertIndex,
133: UInt32 *insertNodeNum,
134: UInt16 *recsRotated );
135:
136:
137:
138: static OSStatus InsertLevel (BTreeControlBlockPtr btreePtr,
139: TreePathTable treePathTable,
140: InsertKey *primaryKey,
141: InsertKey *secondaryKey,
142: BlockDescriptor *targetNode,
143: UInt16 index,
144: UInt16 level,
145: UInt32 *insertNode );
146:
147: static OSErr InsertNode (BTreeControlBlockPtr btreePtr,
148: InsertKey *key,
149: BlockDescriptor *rightNode,
150: UInt32 node,
151: UInt16 index,
152: UInt32 *newNode,
153: UInt16 *newIndex,
154: BlockDescriptor *leftNode,
155: Boolean *updateParent,
156: Boolean *insertParent,
157: Boolean *rootSplit );
158:
159: static UInt16 GetKeyLength (const BTreeControlBlock *btreePtr,
160: const BTreeKey *key,
161: Boolean forLeafNode );
162:
163:
164:
165: //////////////////////// BTree Multi-node Tree Operations ///////////////////////
166:
167:
168: /*-------------------------------------------------------------------------------
169:
170: Routine: SearchTree - Search BTree for key and set up Tree Path Table.
171:
172: Function: Searches BTree for specified key, setting up the Tree Path Table to
173: reflect the search path.
174:
175:
176: Input: btreePtr - pointer to control block of BTree to search
177: keyPtr - pointer to the key to search for
178: treePathTable - pointer to the tree path table to construct
179:
180: Output: nodeNum - number of the node containing the key position
181: iterator - BTreeIterator specifying record or insert position
182:
183: Result: noErr - key found, index is record index
184: fsBTRecordNotFoundErr - key not found, index is insert index
185: fsBTEmptyErr - key not found, return params are nil
186: otherwise - catastrophic failure (GetNode/ReleaseNode failed)
187: -------------------------------------------------------------------------------*/
188:
189: OSStatus SearchTree (BTreeControlBlockPtr btreePtr,
190: BTreeKeyPtr searchKey,
191: TreePathTable treePathTable,
192: UInt32 *nodeNum,
193: BlockDescriptor *nodePtr,
194: UInt16 *returnIndex )
195: {
196: OSStatus err;
197: SInt16 level;
198: UInt32 curNodeNum;
199: NodeRec nodeRec;
200: UInt16 index;
201: Boolean keyFound;
202: KeyPtr keyPtr;
203: UInt8 * dataPtr;
204: UInt16 dataSize;
205:
206:
207: if (btreePtr->treeDepth == 0) // is the tree empty?
208: {
209: err = fsBTEmptyErr;
210: goto ErrorExit;
211: }
212:
213: curNodeNum = btreePtr->rootNode;
214:
215: //�� for debugging...
216: treePathTable [0].node = 0;
217: treePathTable [0].index = 0;
218:
219: while (true)
220: {
221: PanicIf(curNodeNum == 0, "\pSearchTree: curNodeNum is zero!");
222:
223: err = GetNode (btreePtr, curNodeNum, &nodeRec);
224: if (err != noErr)
225: {
226: goto ErrorExit;
227: }
228:
229: keyFound = SearchNode (btreePtr, nodeRec.buffer, searchKey, &index);
230:
231: level = ((BTNodeDescriptor*)nodeRec.buffer)->height; //�� or --level;
232:
233:
234: treePathTable [level].node = curNodeNum;
235:
236: if ( ((BTNodeDescriptor*)nodeRec.buffer)->kind == kBTLeafNode)
237: {
238: treePathTable [level].index = index;
239: break; // were done...
240: }
241:
242: if ( (keyFound != true) && (index != 0))
243: --index;
244:
245: treePathTable [level].index = index;
246:
247: GetRecordByIndex (btreePtr, nodeRec.buffer, index, &keyPtr, &dataPtr, &dataSize);
248: curNodeNum = *(UInt32 *)dataPtr;
249: err = ReleaseNode (btreePtr, &nodeRec);
250: if (err != noErr)
251: {
252: goto ErrorExit;
253: }
254: }
255:
256: *nodeNum = curNodeNum;
257: *nodePtr = nodeRec;
258: *returnIndex = index;
259:
260: if (keyFound)
261: return noErr; // searchKey found, index identifies record in node
262: else
263: return fsBTRecordNotFoundErr; // searchKey not found, index identifies insert point
264:
265: ErrorExit:
266:
267: *nodeNum = 0;
268: nodePtr->buffer = nil;
269: nodePtr->blockHeader = nil;
270: *returnIndex = 0;
271:
272: return err;
273: }
274:
275:
276:
277:
278: ////////////////////////////////// InsertTree ///////////////////////////////////
279:
280: OSStatus InsertTree ( BTreeControlBlockPtr btreePtr,
281: TreePathTable treePathTable,
282: KeyPtr keyPtr,
283: UInt8 * recPtr,
284: UInt16 recSize,
285: BlockDescriptor *targetNode,
286: UInt16 index,
287: UInt16 level,
288: Boolean replacingKey,
289: UInt32 *insertNode )
290: {
291: InsertKey primaryKey;
292: OSStatus err;
293:
294: primaryKey.keyPtr = keyPtr;
295: primaryKey.keyLength = GetKeyLength(btreePtr, primaryKey.keyPtr, (level == 1));
296: primaryKey.recPtr = recPtr;
297: primaryKey.recSize = recSize;
298: primaryKey.replacingKey = replacingKey;
299: primaryKey.skipRotate = false;
300:
301: err = InsertLevel (btreePtr, treePathTable, &primaryKey, nil,
302: targetNode, index, level, insertNode );
303:
304: return err;
305:
306: } // End of InsertTree
307:
308:
309: ////////////////////////////////// InsertLevel //////////////////////////////////
310:
311: OSStatus InsertLevel (BTreeControlBlockPtr btreePtr,
312: TreePathTable treePathTable,
313: InsertKey *primaryKey,
314: InsertKey *secondaryKey,
315: BlockDescriptor *targetNode,
316: UInt16 index,
317: UInt16 level,
318: UInt32 *insertNode )
319: {
320: OSStatus err;
321: BlockDescriptor leftNode;
322: UInt32 targetNodeNum;
323: UInt32 newNodeNum;
324: UInt16 newIndex;
325: Boolean insertParent;
326: Boolean updateParent;
327: Boolean newRoot;
328:
329: #if defined(applec) && !defined(__SC__)
330: PanicIf ((level == 1) && (((NodeDescPtr)targetNode->buffer)->kind != kBTLeafNode), "\P InsertLevel: non-leaf at level 1! ");
331: #endif
332: leftNode.buffer = nil;
333: targetNodeNum = treePathTable [level].node;
334:
335: insertParent = false;
336: updateParent = false;
337:
338: ////// process first insert //////
339:
340: err = InsertNode (btreePtr, primaryKey, targetNode, targetNodeNum, index,
341: &newNodeNum, &newIndex, &leftNode, &updateParent, &insertParent, &newRoot );
342: M_ExitOnError (err);
343:
344: if ( newRoot )
345: {
346: // Extend the treePathTable by adding an entry for the new
347: // root node that references the current targetNode.
348: //
349: // If inserting the secondaryKey changes the first key of
350: // the target node, then we'll have to update the second
351: // key in the new root node.
352:
353: treePathTable [level + 1].node = btreePtr->rootNode;
354: treePathTable [level + 1].index = 1; // 1 since we always split/rotate left
355: }
356:
357: if ( level == 1 )
358: *insertNode = newNodeNum;
359:
360: ////// process second insert (if any) //////
361:
362: if ( secondaryKey != nil )
363: {
364: Boolean temp;
365:
366: err = InsertNode (btreePtr, secondaryKey, targetNode, newNodeNum, newIndex,
367: &newNodeNum, &newIndex, &leftNode, &updateParent, &insertParent, &temp);
368: M_ExitOnError (err);
369:
370: if ( DEBUG_BUILD && updateParent && newRoot )
371: DebugStr("\p InsertLevel: New root from primary key, update from secondary key...");
372: }
373:
374: //////////////////////// Update Parent(s) ///////////////////////////////
375:
376: if ( insertParent || updateParent )
377: {
378: BlockDescriptor parentNode;
379: UInt32 parentNodeNum;
380: KeyPtr keyPtr;
381: UInt8 * recPtr;
382: UInt16 recSize;
383:
384: secondaryKey = nil;
385:
386: PanicIf ( (level == btreePtr->treeDepth), "\p InsertLevel: unfinished insert!?");
387:
388: ++level;
389:
390: // Get Parent Node data...
391: index = treePathTable [level].index;
392: parentNodeNum = treePathTable [level].node;
393:
394: PanicIf ( parentNodeNum == 0, "\p InsertLevel: parent node is zero!?");
395:
396: err = GetNode (btreePtr, parentNodeNum, &parentNode); // released as target node in next level up
397: M_ExitOnError (err);
398: #if defined(applec) && !defined(__SC__)
399: if (DEBUG_BUILD && level > 1)
400: PanicIf ( ((NodeDescPtr)parentNode.buffer)->kind != kBTIndexNode, "\P InsertLevel: parent node not an index node! ");
401: #endif
402: ////////////////////////// Update Parent Index //////////////////////////////
403:
404: if ( updateParent )
405: {
406: //���debug: check if ptr == targetNodeNum
407: GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize);
408: PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "\p InsertLevel: parent ptr doesn't match target node!");
409:
410: // need to delete and re-insert this parent key/ptr
411: // we delete it here and it gets re-inserted in the
412: // InsertLevel call below.
413: DeleteRecord (btreePtr, parentNode.buffer, index);
414:
415: primaryKey->keyPtr = (KeyPtr) GetRecordAddress( btreePtr, targetNode->buffer, 0 );
416: primaryKey->keyLength = GetKeyLength(btreePtr, primaryKey->keyPtr, false);
417: primaryKey->recPtr = (UInt8 *) &targetNodeNum;
418: primaryKey->recSize = sizeof(targetNodeNum);
419: primaryKey->replacingKey = kReplaceRecord;
420: primaryKey->skipRotate = insertParent; // don't rotate left if we have two inserts occuring
421: }
422:
423: ////////////////////////// Add New Parent Index /////////////////////////////
424:
425: if ( insertParent )
426: {
427: InsertKey *insertKeyPtr;
428: InsertKey insertKey;
429:
430: if ( updateParent )
431: {
432: insertKeyPtr = &insertKey;
433: secondaryKey = &insertKey;
434: }
435: else
436: {
437: insertKeyPtr = primaryKey;
438: }
439:
440: insertKeyPtr->keyPtr = (KeyPtr) GetRecordAddress (btreePtr, leftNode.buffer, 0);
441: insertKeyPtr->keyLength = GetKeyLength(btreePtr, insertKeyPtr->keyPtr, false);
442: insertKeyPtr->recPtr = (UInt8 *) &((NodeDescPtr)targetNode->buffer)->bLink;
443: insertKeyPtr->recSize = sizeof(UInt32);
444: insertKeyPtr->replacingKey = kInsertRecord;
445: insertKeyPtr->skipRotate = false; // a rotate is OK during second insert
446: }
447:
448: err = InsertLevel (btreePtr, treePathTable, primaryKey, secondaryKey,
449: &parentNode, index, level, insertNode );
450: M_ExitOnError (err);
451: }
452:
453: err = UpdateNode (btreePtr, targetNode, 0, kLockTransaction); // all done with target
454: M_ExitOnError (err);
455:
456: err = UpdateNode (btreePtr, &leftNode, 0, kLockTransaction); // all done with left sibling
457: M_ExitOnError (err);
458:
459: return noErr;
460:
461: ErrorExit:
462:
463: (void) ReleaseNode (btreePtr, targetNode);
464: (void) ReleaseNode (btreePtr, &leftNode);
465:
466: Panic ("\p InsertLevel: an error occured!");
467:
468: return err;
469:
470: } // End of InsertLevel
471:
472:
473:
474: ////////////////////////////////// InsertNode ///////////////////////////////////
475:
476: static OSErr InsertNode (BTreeControlBlockPtr btreePtr,
477: InsertKey *key,
478:
479: BlockDescriptor *rightNode,
480: UInt32 node,
481: UInt16 index,
482:
483: UInt32 *newNode,
484: UInt16 *newIndex,
485:
486: BlockDescriptor *leftNode,
487: Boolean *updateParent,
488: Boolean *insertParent,
489: Boolean *rootSplit )
490: {
491: BlockDescriptor *targetNode;
492: UInt32 leftNodeNum;
493: UInt16 recsRotated;
494: OSErr err;
495: Boolean recordFit;
496:
497: *rootSplit = false;
498:
499: PanicIf ( rightNode->buffer == leftNode->buffer, "\p InsertNode: rightNode == leftNode, huh?");
500:
501: leftNodeNum = ((NodeDescPtr) rightNode->buffer)->bLink;
502:
503:
504: /////////////////////// Try Simple Insert ///////////////////////////////
505:
506: if ( node == leftNodeNum )
507: targetNode = leftNode;
508: else
509: targetNode = rightNode;
510:
511: recordFit = InsertKeyRecord (btreePtr, targetNode->buffer, index, key->keyPtr, key->keyLength, key->recPtr, key->recSize);
512:
513: if ( recordFit )
514: {
515: *newNode = node;
516: *newIndex = index;
517:
518: if ( (index == 0) && (((NodeDescPtr) targetNode->buffer)->height != btreePtr->treeDepth) )
519: *updateParent = true; // the first record changed so we need to update the parent
520: }
521:
522:
523: //////////////////////// Try Rotate Left ////////////////////////////////
524:
525: if ( !recordFit && leftNodeNum > 0 )
526: {
527: PanicIf ( leftNode->buffer != nil, "\p InsertNode: leftNode already aquired!");
528:
529: if ( leftNode->buffer == nil )
530: {
531: err = GetNode (btreePtr, leftNodeNum, leftNode); // will be released by caller or a split below
532: M_ExitOnError (err);
533: }
534:
535: PanicIf ( ((NodeDescPtr) leftNode->buffer)->fLink != node, "\p InsertNode, RotateLeft: invalid sibling link!" );
536:
537: if ( !key->skipRotate ) // are rotates allowed?
538: {
539: err = RotateLeft (btreePtr, leftNode->buffer, rightNode->buffer, index, key->keyPtr, key->recPtr,
540: key->recSize, newIndex, newNode, &recordFit, &recsRotated );
541: M_ExitOnError (err);
542:
543: if ( recordFit )
544: {
545: if ( key->replacingKey || (recsRotated > 1) || (index > 0) )
546: *updateParent = true;
547: }
548: }
549: }
550:
551:
552: //////////////////////// Try Split Left /////////////////////////////////
553:
554: if ( !recordFit )
555: {
556: // might not have left node...
557: err = SplitLeft (btreePtr, leftNode, rightNode, node, index, key->keyPtr,
558: key->recPtr, key->recSize, newIndex, newNode, &recsRotated);
559: M_ExitOnError (err);
560:
561: // if we split root node - add new root
562:
563: if ( ((NodeDescPtr) rightNode->buffer)->height == btreePtr->treeDepth )
564: {
565: err = AddNewRootNode (btreePtr, leftNode->buffer, rightNode->buffer); // Note: does not update TPT
566: M_ExitOnError (err);
567: *rootSplit = true;
568: }
569: else
570: {
571: *insertParent = true;
572:
573: if ( key->replacingKey || (recsRotated > 1) || (index > 0) )
574: *updateParent = true;
575: }
576: }
577:
578: return noErr;
579:
580: ErrorExit:
581:
582: (void) ReleaseNode (btreePtr, leftNode);
583: return err;
584:
585: } // End of InsertNode
586:
587:
588: /*-------------------------------------------------------------------------------
589: Routine: DeleteTree - One_line_description.
590:
591: Function: Brief_description_of_the_function_and_any_side_effects
592:
593: ToDo:
594:
595: Input: btreePtr - description
596: treePathTable - description
597: targetNode - description
598: index - description
599:
600: Result: noErr - success
601: != noErr - failure
602: -------------------------------------------------------------------------------*/
603:
604: OSStatus DeleteTree (BTreeControlBlockPtr btreePtr,
605: TreePathTable treePathTable,
606: BlockDescriptor *targetNode,
607: UInt16 index,
608: UInt16 level )
609: {
610: OSStatus err;
611: BlockDescriptor parentNode;
612: BTNodeDescriptor *targetNodePtr;
613: UInt32 targetNodeNum;
614: Boolean deleteRequired;
615: Boolean updateRequired;
616:
617:
618: deleteRequired = false;
619: updateRequired = false;
620:
621: targetNodeNum = treePathTable[level].node;
622: targetNodePtr = targetNode->buffer;
623: PanicIf (targetNodePtr == nil, "\pDeleteTree: targetNode has nil buffer!");
624:
625: DeleteRecord (btreePtr, targetNodePtr, index);
626:
627: //�� coalesce remaining records?
628:
629: if ( targetNodePtr->numRecords == 0 ) // did we delete the last record?
630: {
631: BlockDescriptor siblingNode;
632: UInt32 siblingNodeNum;
633:
634: deleteRequired = true;
635:
636: ////////////////// Get Siblings & Update Links //////////////////////////
637:
638: siblingNodeNum = targetNodePtr->bLink; // Left Sibling Node
639: if ( siblingNodeNum != 0 )
640: {
641: err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
642: M_ExitOnError (err);
643: ((NodeDescPtr)siblingNode.buffer)->fLink = targetNodePtr->fLink;
644: err = UpdateNode (btreePtr, &siblingNode, 0, kLockTransaction);
645: M_ExitOnError (err);
646: }
647: else if ( targetNodePtr->kind == kBTLeafNode ) // update firstLeafNode
648: {
649: btreePtr->firstLeafNode = targetNodePtr->fLink;
650: }
651:
652: siblingNodeNum = targetNodePtr->fLink; // Right Sibling Node
653: if ( siblingNodeNum != 0 )
654: {
655: err = GetNode (btreePtr, siblingNodeNum, &siblingNode);
656: M_ExitOnError (err);
657: ((NodeDescPtr)siblingNode.buffer)->bLink = targetNodePtr->bLink;
658: err = UpdateNode (btreePtr, &siblingNode, 0, kLockTransaction);
659: M_ExitOnError (err);
660: }
661: else if ( targetNodePtr->kind == kBTLeafNode ) // update lastLeafNode
662: {
663: btreePtr->lastLeafNode = targetNodePtr->bLink;
664: }
665:
666: //////////////////////// Free Empty Node ////////////////////////////////
667:
668: ClearNode (btreePtr, targetNodePtr);
669:
670: err = UpdateNode (btreePtr, targetNode, 0, kLockTransaction);
671: M_ExitOnError (err);
672: err = FreeNode (btreePtr, targetNodeNum);
673: M_ExitOnError (err);
674: }
675: else if ( index == 0 ) // did we delete the first record?
676: {
677: updateRequired = true; // yes, so we need to update parent
678: }
679:
680:
681: if ( level == btreePtr->treeDepth ) // then targetNode->buffer is the root node
682: {
683: deleteRequired = false;
684: updateRequired = false;
685:
686: if ( targetNode->buffer == nil ) // then root was freed and the btree is empty
687: {
688: btreePtr->rootNode = 0;
689: btreePtr->treeDepth = 0;
690: }
691: else if ( ((NodeDescPtr)targetNode->buffer)->numRecords == 1 )
692: {
693: err = CollapseTree (btreePtr, targetNode);
694: M_ExitOnError (err);
695: }
696: }
697:
698:
699: if ( updateRequired || deleteRequired )
700: {
701: ++level; // next level
702:
703: //// Get Parent Node and index
704: index = treePathTable [level].index;
705: err = GetNode (btreePtr, treePathTable[level].node, &parentNode);
706: M_ExitOnError (err);
707:
708: if ( updateRequired )
709: {
710: KeyPtr keyPtr;
711: UInt8 * recPtr;
712: UInt16 recSize;
713: UInt32 insertNode;
714:
715: //���debug: check if ptr == targetNodeNum
716: GetRecordByIndex (btreePtr, parentNode.buffer, index, &keyPtr, &recPtr, &recSize);
717: PanicIf( (*(UInt32 *) recPtr) != targetNodeNum, "\p DeleteTree: parent ptr doesn't match targetNodeNum!!");
718:
719: // need to delete and re-insert this parent key/ptr
720: DeleteRecord (btreePtr, parentNode.buffer, index);
721:
722: keyPtr = (KeyPtr) GetRecordAddress( btreePtr, targetNode->buffer, 0 );
723: recPtr = (UInt8 *) &targetNodeNum;
724: recSize = sizeof(targetNodeNum);
725:
726: err = InsertTree (btreePtr, treePathTable, keyPtr, recPtr, recSize,
727: &parentNode, index, level, kReplaceRecord, &insertNode);
728: M_ExitOnError (err);
729: }
730: else // deleteRequired
731: {
732: err = DeleteTree (btreePtr, treePathTable, &parentNode, index, level);
733: M_ExitOnError (err);
734: }
735: }
736:
737:
738: err = UpdateNode (btreePtr, targetNode, 0, kLockTransaction);
739: M_ExitOnError (err);
740:
741: return noErr;
742:
743: ErrorExit:
744:
745: (void) ReleaseNode (btreePtr, targetNode);
746: (void) ReleaseNode (btreePtr, &parentNode);
747:
748: return err;
749:
750: } // end DeleteTree
751:
752:
753:
754: ///////////////////////////////// CollapseTree //////////////////////////////////
755:
756: static OSStatus CollapseTree (BTreeControlBlockPtr btreePtr,
757: BlockDescriptor *blockPtr )
758: {
759: OSStatus err;
760: UInt32 originalRoot;
761: UInt32 nodeNum;
762:
763: originalRoot = btreePtr->rootNode;
764:
765: while (true)
766: {
767: if ( ((NodeDescPtr)blockPtr->buffer)->numRecords > 1)
768: break; // this will make a fine root node
769:
770: if ( ((NodeDescPtr)blockPtr->buffer)->kind == kBTLeafNode)
771: break; // we've hit bottom
772:
773: nodeNum = btreePtr->rootNode;
774: btreePtr->rootNode = GetChildNodeNum (btreePtr, blockPtr->buffer, 0);
775: --btreePtr->treeDepth;
776:
777: //// Clear and Free Current Old Root Node ////
778: ClearNode (btreePtr, blockPtr->buffer);
779: err = UpdateNode (btreePtr, blockPtr, 0, kLockTransaction);
780: M_ExitOnError (err);
781: err = FreeNode (btreePtr, nodeNum);
782: M_ExitOnError (err);
783:
784: //// Get New Root Node
785: err = GetNode (btreePtr, btreePtr->rootNode, blockPtr);
786: M_ExitOnError (err);
787: }
788:
789: if (btreePtr->rootNode != originalRoot)
790: M_BTreeHeaderDirty (btreePtr);
791:
792: err = UpdateNode (btreePtr, blockPtr, 0, kLockTransaction); // always update!
793: M_ExitOnError (err);
794:
795: return noErr;
796:
797:
798: /////////////////////////////////// ErrorExit ///////////////////////////////////
799:
800: ErrorExit:
801: (void) ReleaseNode (btreePtr, blockPtr);
802: return err;
803: }
804:
805:
806:
807: ////////////////////////////////// RotateLeft ///////////////////////////////////
808:
809: /*-------------------------------------------------------------------------------
810:
811: Routine: RotateLeft - One_line_description.
812:
813: Function: Brief_description_of_the_function_and_any_side_effects
814:
815: Algorithm: if rightIndex > insertIndex, subtract 1 for actual rightIndex
816:
817: Input: btreePtr - description
818: leftNode - description
819: rightNode - description
820: rightInsertIndex - description
821: keyPtr - description
822: recPtr - description
823: recSize - description
824:
825: Output: insertIndex
826: insertNodeNum - description
827: recordFit - description
828: recsRotated
829:
830: Result: noErr - success
831: != noErr - failure
832: -------------------------------------------------------------------------------*/
833:
834: static OSStatus RotateLeft (BTreeControlBlockPtr btreePtr,
835: NodeDescPtr leftNode,
836: NodeDescPtr rightNode,
837: UInt16 rightInsertIndex,
838: KeyPtr keyPtr,
839: UInt8 * recPtr,
840: UInt16 recSize,
841: UInt16 *insertIndex,
842: UInt32 *insertNodeNum,
843: Boolean *recordFit,
844: UInt16 *recsRotated )
845: {
846: OSStatus err;
847: SInt32 insertSize;
848: SInt32 nodeSize;
849: SInt32 leftSize, rightSize;
850: SInt32 moveSize = 0;
851: UInt16 keyLength;
852: UInt16 lengthFieldSize;
853: UInt16 index, moveIndex;
854: Boolean didItFit;
855:
856: ///////////////////// Determine If Record Will Fit //////////////////////////
857:
858: keyLength = GetKeyLength(btreePtr, keyPtr, (rightNode->kind == kBTLeafNode));
859:
860: // the key's length field is 8-bits in HFS and 16-bits in HFS+
861: if ( btreePtr->attributes & kBTBigKeysMask )
862: lengthFieldSize = sizeof(UInt16);
863: else
864: lengthFieldSize = sizeof(UInt8);
865:
866: insertSize = keyLength + lengthFieldSize + recSize + sizeof(UInt16);
867:
868: if ( M_IsOdd (insertSize) )
869: ++insertSize; // add pad byte;
870:
871: nodeSize = btreePtr->nodeSize;
872:
873: // add size of insert record to right node
874: rightSize = nodeSize - GetNodeFreeSize (btreePtr, rightNode) + insertSize;
875: leftSize = nodeSize - GetNodeFreeSize (btreePtr, leftNode);
876:
877: moveIndex = 0;
878:
879: while ( leftSize < rightSize )
880: {
881: if ( moveIndex < rightInsertIndex )
882: {
883: moveSize = GetRecordSize (btreePtr, rightNode, moveIndex) + 2;
884: }
885: else if ( moveIndex == rightInsertIndex )
886: {
887: moveSize = insertSize;
888: }
889: else // ( moveIndex > rightInsertIndex )
890: {
891: moveSize = GetRecordSize (btreePtr, rightNode, moveIndex - 1) + 2;
892: }
893:
894: leftSize += moveSize;
895: rightSize -= moveSize;
896: ++moveIndex;
897: }
898:
899: if ( leftSize > nodeSize ) // undo last move
900: {
901: leftSize -= moveSize;
902: rightSize += moveSize;
903: --moveIndex;
904: }
905:
906: if ( rightSize > nodeSize ) // record won't fit - failure, but not error
907: {
908: *insertIndex = 0;
909: *insertNodeNum = 0;
910: *recordFit = false;
911: *recsRotated = 0;
912:
913: return noErr;
914: }
915:
916: // we've found balance point, moveIndex == number of records moved into leftNode
917:
918:
919: //////////////////////////// Rotate Records /////////////////////////////////
920:
921: *recsRotated = moveIndex;
922: *recordFit = true;
923: index = 0;
924:
925: while ( index < moveIndex )
926: {
927: if ( index == rightInsertIndex ) // insert new record in left node
928: {
929: UInt16 leftInsertIndex;
930:
931: leftInsertIndex = leftNode->numRecords;
932:
933: didItFit = InsertKeyRecord (btreePtr, leftNode, leftInsertIndex,
934: keyPtr, keyLength, recPtr, recSize);
935: if ( !didItFit )
936: {
937: Panic ("\pRotateLeft: InsertKeyRecord (left) returned false!");
938: err = fsBTBadRotateErr;
939: goto ErrorExit;
940: }
941:
942: *insertIndex = leftInsertIndex;
943: *insertNodeNum = rightNode->bLink;
944: }
945: else
946: {
947: didItFit = RotateRecordLeft (btreePtr, leftNode, rightNode);
948: if ( !didItFit )
949: {
950: Panic ("\pRotateLeft: RotateRecordLeft returned false!");
951: err = fsBTBadRotateErr;
952: goto ErrorExit;
953: }
954: }
955:
956: ++index;
957: }
958:
959: if ( moveIndex <= rightInsertIndex ) // then insert new record in right node
960: {
961: rightInsertIndex -= index; // adjust for records already rotated
962:
963: didItFit = InsertKeyRecord (btreePtr, rightNode, rightInsertIndex,
964: keyPtr, keyLength, recPtr, recSize);
965: if ( !didItFit )
966: {
967: Panic ("\pRotateLeft: InsertKeyRecord (right) returned false!");
968: err = fsBTBadRotateErr;
969: goto ErrorExit;
970: }
971:
972: *insertIndex = rightInsertIndex;
973: *insertNodeNum = leftNode->fLink;
974: }
975:
976:
977: return noErr;
978:
979:
980: ////////////////////////////// Error Exit ///////////////////////////////////
981:
982: ErrorExit:
983:
984: *insertIndex = 0;
985: *insertNodeNum = 0;
986: *recordFit = false;
987: *recsRotated = 0;
988:
989: return err;
990: }
991:
992:
993:
994: /////////////////////////////////// SplitLeft ///////////////////////////////////
995:
996: static OSStatus SplitLeft (BTreeControlBlockPtr btreePtr,
997: BlockDescriptor *leftNode,
998: BlockDescriptor *rightNode,
999: UInt32 rightNodeNum,
1000: UInt16 index,
1001: KeyPtr keyPtr,
1002: UInt8 * recPtr,
1003: UInt16 recSize,
1004: UInt16 *insertIndex,
1005: UInt32 *insertNodeNum,
1006: UInt16 *recsRotated )
1007: {
1008: OSStatus err;
1009: NodeDescPtr left, right;
1010: UInt32 newNodeNum;
1011: Boolean recordFit;
1012:
1013:
1014: ///////////////////////////// Compare Nodes /////////////////////////////////
1015:
1016: right = rightNode->buffer;
1017: left = leftNode->buffer;
1018:
1019: PanicIf ( right->bLink != 0 && left == 0, "\p SplitLeft: left sibling missing!?" );
1020:
1021: /* type should be kBTLeafNode or kBTIndexNode */
1022:
1023: if ( (right->height == 1) && (right->kind != kBTLeafNode) )
1024: return fsBTInvalidNodeErr;
1025:
1026: if ( left != nil )
1027: {
1028: if ( left->fLink != rightNodeNum )
1029: return fsBTInvalidNodeErr; //�� E_BadSibling ?
1030:
1031: if ( left->height != right->height )
1032: return fsBTInvalidNodeErr; //�� E_BadNodeHeight ?
1033:
1034: if ( left->kind != right->kind )
1035: return fsBTInvalidNodeErr; //�� E_BadNodeType ?
1036: }
1037:
1038:
1039: ///////////////////////////// Allocate Node /////////////////////////////////
1040:
1041: err = AllocateNode (btreePtr, &newNodeNum);
1042: M_ExitOnError (err);
1043:
1044:
1045: /////////////// Update Forward Link In Original Left Node ///////////////////
1046:
1047: if ( left != nil )
1048: {
1049: left->fLink = newNodeNum;
1050: err = UpdateNode (btreePtr, leftNode, 0, kLockTransaction);
1051: M_ExitOnError (err);
1052: }
1053:
1054:
1055: /////////////////////// Initialize New Left Node ////////////////////////////
1056:
1057: err = GetNewNode (btreePtr, newNodeNum, leftNode);
1058: M_ExitOnError (err);
1059:
1060: left = leftNode->buffer;
1061: left->fLink = rightNodeNum;
1062:
1063:
1064: // Steal Info From Right Node
1065:
1066: left->bLink = right->bLink;
1067: left->kind = right->kind;
1068: left->height = right->height;
1069:
1070: right->bLink = newNodeNum; // update Right bLink
1071:
1072: if ( (left->kind == kBTLeafNode) && (left->bLink == 0) )
1073: {
1074: // if we're adding a new first leaf node - update BTreeInfoRec
1075:
1076: btreePtr->firstLeafNode = newNodeNum;
1077: M_BTreeHeaderDirty (btreePtr); //�� AllocateNode should have set the bit already...
1078: }
1079:
1080: ////////////////////////////// Rotate Left //////////////////////////////////
1081:
1082: err = RotateLeft (btreePtr, left, right, index, keyPtr, recPtr, recSize,
1083: insertIndex, insertNodeNum, &recordFit, recsRotated);
1084: M_ExitOnError (err);
1085:
1086: return noErr;
1087:
1088: ErrorExit:
1089:
1090: (void) ReleaseNode (btreePtr, leftNode);
1091: (void) ReleaseNode (btreePtr, rightNode);
1092:
1093: //�� Free new node if allocated?
1094:
1095: *insertIndex = 0;
1096: *insertNodeNum = 0;
1097: *recsRotated = 0;
1098:
1099: return err;
1100: }
1101:
1102:
1103:
1104: /////////////////////////////// RotateRecordLeft ////////////////////////////////
1105:
1106: static Boolean RotateRecordLeft (BTreeControlBlockPtr btreePtr,
1107: NodeDescPtr leftNode,
1108: NodeDescPtr rightNode )
1109: {
1110: UInt16 size;
1111: UInt8 * recPtr;
1112: Boolean recordFit;
1113:
1114: size = GetRecordSize (btreePtr, rightNode, 0);
1115: recPtr = GetRecordAddress (btreePtr, rightNode, 0);
1116:
1117: recordFit = InsertRecord (btreePtr, leftNode, leftNode->numRecords, recPtr, size);
1118:
1119: if ( !recordFit )
1120: return false;
1121:
1122: DeleteRecord (btreePtr, rightNode, 0);
1123:
1124: return true;
1125: }
1126:
1127:
1128: //////////////////////////////// AddNewRootNode /////////////////////////////////
1129:
1130: static OSStatus AddNewRootNode (BTreeControlBlockPtr btreePtr,
1131: NodeDescPtr leftNode,
1132: NodeDescPtr rightNode )
1133: {
1134: OSStatus err;
1135: BlockDescriptor rootNode;
1136: UInt32 rootNum;
1137: KeyPtr keyPtr;
1138: Boolean didItFit;
1139: UInt16 keyLength;
1140:
1141: PanicIf (leftNode == nil, "\pAddNewRootNode: leftNode == nil");
1142: PanicIf (rightNode == nil, "\pAddNewRootNode: rightNode == nil");
1143:
1144:
1145: /////////////////////// Initialize New Root Node ////////////////////////////
1146:
1147: err = AllocateNode (btreePtr, &rootNum);
1148: M_ExitOnError (err);
1149:
1150: err = GetNewNode (btreePtr, rootNum, &rootNode);
1151: M_ExitOnError (err);
1152:
1153: ((NodeDescPtr)rootNode.buffer)->kind = kBTIndexNode;
1154: ((NodeDescPtr)rootNode.buffer)->height = ++btreePtr->treeDepth;
1155:
1156:
1157: ///////////////////// Insert Left Node Index Record /////////////////////////
1158:
1159: keyPtr = (KeyPtr) GetRecordAddress (btreePtr, leftNode, 0);
1160: keyLength = GetKeyLength(btreePtr, keyPtr, false);
1161:
1162: didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 0, keyPtr, keyLength,
1163: (UInt8 *) &rightNode->bLink, 4 );
1164:
1165: PanicIf ( !didItFit, "\pAddNewRootNode:InsertKeyRecord failed for left index record");
1166:
1167:
1168: //////////////////// Insert Right Node Index Record /////////////////////////
1169:
1170: keyPtr = (KeyPtr) GetRecordAddress (btreePtr, rightNode, 0);
1171: keyLength = GetKeyLength(btreePtr, keyPtr, false);
1172:
1173: didItFit = InsertKeyRecord ( btreePtr, rootNode.buffer, 1, keyPtr, keyLength,
1174: (UInt8 *) &leftNode->fLink, 4 );
1175:
1176: PanicIf ( !didItFit, "\pAddNewRootNode:InsertKeyRecord failed for right index record");
1177:
1178:
1179: /////////////////////////// Release Root Node ///////////////////////////////
1180:
1181: err = UpdateNode (btreePtr, &rootNode, 0, kLockTransaction);
1182: M_ExitOnError (err);
1183:
1184: // update BTreeInfoRec
1185:
1186: btreePtr->rootNode = rootNum;
1187: btreePtr->flags |= kBTHeaderDirty;
1188:
1189: return noErr;
1190:
1191:
1192: ////////////////////////////// Error Exit ///////////////////////////////////
1193:
1194: ErrorExit:
1195:
1196: return err;
1197: }
1198:
1199:
1200: static UInt16 GetKeyLength ( const BTreeControlBlock *btreePtr, const BTreeKey *key, Boolean forLeafNode )
1201: {
1202: UInt16 length;
1203:
1204: if ( forLeafNode || btreePtr->attributes & kBTVariableIndexKeysMask )
1205: length = KeyLength (btreePtr, key); // just use actual key length
1206: else
1207: length = btreePtr->maxKeyLength; // fixed sized index key (i.e. HFS) //�� shouldn't we clear the pad bytes?
1208:
1209: return length;
1210: }
1211:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.