|
|
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.