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