|
|
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: BTreeNodeOps.c
24:
25: Contains: Single-node 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: (djb) Don Brady
45:
46: Change History (most recent first):
47:
48: <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
49: <MOSXS> 4/113/99 djb Fix key size checking bug in CheckNode.
50: <MOSXS> 3/19/99 djb Added key size checking to CheckNode.
51: <MOSXS> 3/26/98 djb Added PrintNode for debugging.
52: <CS5> 9/4/97 djb Removed GetRightSiblingNode and GetLeftSiblingNode - they are
53: now macros. SearchNode is now in BTreeSearchNode.a.
54: <CS4> 8/22/97 djb Turn off debugging code in CheckKey.
55: <CS3> 7/24/97 djb Add summary traces for Get/Rel Node. Made GetRecordOffset into a
56: macro. Only call CheckNode if the node came from disk.
57: <CS2> 7/21/97 msd Make GetRecordByIndex check its record index input; it now
58: returns an OSStatus.
59: <CS1> 4/23/97 djb first checked in
60:
61: <HFS3> 2/19/97 djb Changes to support big node cache.
62: <HFS2> 1/3/97 djb Added support for large keys.
63: <HFS1> 12/19/96 djb first checked in
64:
65:
66: History applicable to original Scarecrow Design:
67:
68: <6> 10/25/96 ser Changing for new VFPI
69: <5> 9/17/96 dkh Add bounds checking to GetNode. Update GetNode to not assert
70: that CheckNode failed if the node is all zeroes. This can happen
71: if the hint case if the fetched node has been deallocated
72: <4> 3/7/96 dkh Change GetNewNode() to not use kGetEmptyBlock. Instead use
73: kGetBlock to fetch a block from the disk itself. ��� Why?
74: <3> 1/22/96 dkh Add #include Memory.h
75: <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
76: <1> 10/18/95 rst Moved from Scarecrow project.
77:
78: <17> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
79: <16> 1/31/95 prp GetBlockProc interface uses a 64 bit node number.
80: <15> 1/12/95 wjk Adopt Model FileSystem changes in D5.
81: <14> 9/30/94 prp Get in sync with D2 interface changes.
82: <13> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
83: <12> 7/22/94 wjk Convert to the new set of header files.
84: <11> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
85: NRCmds environments.
86: <10> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
87: agree with their prototypes.
88: <9> 8/31/93 prp Use U64SetU instead of S64Set.
89: <8> 5/21/93 gs Maintain statistical counters on Get/Release node routines.
90: <7> 5/10/93 gs Change keySize parameter to keyLength for InsertKeyRecord
91: routine. Calculate number of bytes in key from keyLength to
92: account for length and pad bytes. Add GetChildNodeNum routine.
93: <6> 3/23/93 gs Add InsertKeyRecord routine.
94: <5> 2/8/93 gs Fix bug in SearchNode that caused "off by 1" error when final
95: compare was searchKey > trialKey. Add UpdateNode.
96: <4> 12/10/92 gs Change keyLength field of key to 'length'.
97: <3> 12/8/92 gs Incorporate suggestions from preliminary code review.
98: <2> 12/2/92 gs Implement routines.
99: <1> 11/15/92 gs Define routine interfaces.
100:
101: */
102:
103: #include "../headers/BTreesPrivate.h"
104: #include "../headers/HFSInstrumentation.h"
105:
106:
107:
108: ///////////////////////// BTree Module Node Operations //////////////////////////
109: //
110: // GetNode - Call FS Agent to get node
111: // GetNewNode - Call FS Agent to get a new node
112: // ReleaseNode - Call FS Agent to release node obtained by GetNode.
113: // UpdateNode - Mark a node as dirty and call FS Agent to release it.
114: //
115: // CheckNode - Checks the validity of a node.
116: // ClearNode - Clear a node to all zeroes.
117: //
118: // InsertRecord - Inserts a record into a BTree node.
119: // InsertKeyRecord - Inserts a key and record pair into a BTree node.
120: // DeleteRecord - Deletes a record from a BTree node.
121: //
122: // SearchNode - Return index for record that matches key.
123: // LocateRecord - Return pointer to key and data, and size of data.
124: //
125: // GetNodeDataSize - Return the amount of space used for data in the node.
126: // GetNodeFreeSize - Return the amount of free space in the node.
127: //
128: // GetRecordOffset - Return the offset for record "index".
129: // GetRecordAddress - Return address of record "index".
130: // GetOffsetAddress - Return address of offset for record "index".
131: //
132: // InsertOffset - Inserts a new offset into a node.
133: // DeleteOffset - Deletes an offset from a node.
134: //
135: // MoveRecordsLeft - Move records left within a node.
136: // MoveRecordsRight - Move records right within a node.
137: //
138: /////////////////////////////////////////////////////////////////////////////////
139:
140:
141:
142: ////////////////////// Routines Internal To BTreeNodeOps.c //////////////////////
143:
144: UInt16 GetRecordOffset (BTreeControlBlockPtr btree,
145: NodeDescPtr node,
146: UInt16 index );
147:
148: UInt16 *GetOffsetAddress (BTreeControlBlockPtr btreePtr,
149: NodeDescPtr node,
150: UInt16 index );
151:
152: void InsertOffset (BTreeControlBlockPtr btreePtr,
153: NodeDescPtr node,
154: UInt16 index,
155: UInt16 delta );
156:
157: void DeleteOffset (BTreeControlBlockPtr btreePtr,
158: NodeDescPtr node,
159: UInt16 index );
160:
161:
162: /////////////////////////////////////////////////////////////////////////////////
163:
164: #define GetRecordOffset(btreePtr,node,index) (*(short *) ((UInt8 *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
165:
166: #if HFS_DIAGNOSTIC
167: #include <sys/systm.h>
168: #define PRINTIT kprintf
169: #endif /* HFS_DIAGNOSTIC */
170:
171: static void PrintNode(const NodeDescPtr node, UInt16 nodeSize, UInt32 nodeNumber);
172:
173:
174:
175: /*-------------------------------------------------------------------------------
176:
177: Routine: GetNode - Call FS Agent to get node
178:
179: Function: Gets an existing BTree node from FS Agent and verifies it.
180:
181: Input: btreePtr - pointer to BTree control block
182: nodeNum - number of node to request
183:
184: Output: nodePtr - pointer to beginning of node (nil if error)
185:
186: Result:
187: noErr - success
188: != noErr - failure
189: -------------------------------------------------------------------------------*/
190:
191: OSStatus GetNode (BTreeControlBlockPtr btreePtr,
192: UInt32 nodeNum,
193: NodeRec *nodePtr )
194: {
195: OSStatus err;
196: GetBlockProcPtr getNodeProc;
197:
198:
199: LogStartTime(kTraceGetNode);
200:
201: //�� is nodeNum within proper range?
202: if( nodeNum >= btreePtr->totalNodes )
203: {
204: Panic("\pGetNode:nodeNum >= totalNodes");
205: err = fsBTInvalidNodeErr;
206: goto ErrorExit;
207: }
208:
209: nodePtr->blockSize = btreePtr->nodeSize; // indicate the size of a node
210:
211: getNodeProc = btreePtr->getBlockProc;
212: err = getNodeProc (btreePtr->fileRefNum,
213: nodeNum,
214: kGetBlock,
215: nodePtr );
216:
217: if (err != noErr)
218: {
219: Panic ("\pGetNode: getNodeProc returned error.");
220: // nodePtr->buffer = nil;
221: goto ErrorExit;
222: }
223: ++btreePtr->numGetNodes;
224:
225: //
226: // Optimization
227: // Only call CheckNode if the node came from disk.
228: // If it was in the cache, we'll assume its already a valid node.
229: //
230:
231: if ( nodePtr->blockReadFromDisk ) // if we read it from disk then check it
232: {
233: err = CheckNode (btreePtr, nodePtr->buffer);
234:
235: if (err != noErr)
236: {
237:
238: VTOVCB(btreePtr->fileRefNum)->vcbFlags |= kHFS_DamagedVolume;
239:
240: #if HFS_DIAGNOSTIC
241: if (((NodeDescPtr)nodePtr->buffer)->numRecords != 0)
242: PrintNode(nodePtr->buffer, btreePtr->nodeSize, nodeNum);
243: #endif
244:
245: if (DEBUG_BUILD)
246: {
247: // With the removal of bounds checking in IsItAHint(), it's possible that
248: // GetNode() will be called to fetch a clear (all zeroes) node. We want
249: // CheckNode() to fail in this case (it does), however we don't want to assert
250: // this case because it is not really an "error". Returning an error from GetNode()
251: // in this case will cause the hint checking code to ignore the hint and revert to
252: // the full search mode.
253:
254: {
255: UInt32 *cur;
256: UInt32 *lastPlusOne;
257:
258: cur = nodePtr->buffer;
259: lastPlusOne = (UInt32 *) ((UInt8 *) cur + btreePtr->nodeSize);
260:
261: while( cur < lastPlusOne )
262: {
263: if( *cur++ != 0 )
264: {
265: Panic ("\pGetNode: CheckNode returned error.");
266: break;
267: }
268: }
269: }
270: }
271:
272: (void) ReleaseNode (btreePtr, nodePtr); // ignore error
273: goto ErrorExit;
274: }
275: }
276:
277: LogEndTime(kTraceGetNode, noErr);
278:
279: return noErr;
280:
281: ErrorExit:
282: nodePtr->buffer = nil;
283: nodePtr->blockHeader = nil;
284:
285: LogEndTime(kTraceGetNode, err);
286:
287: return err;
288: }
289:
290:
291:
292: /*-------------------------------------------------------------------------------
293:
294: Routine: GetNewNode - Call FS Agent to get a new node
295:
296: Function: Gets a new BTree node from FS Agent and initializes it to an empty
297: state.
298:
299: Input: btreePtr - pointer to BTree control block
300: nodeNum - number of node to request
301:
302: Output: returnNodePtr - pointer to beginning of node (nil if error)
303:
304: Result: noErr - success
305: != noErr - failure
306: -------------------------------------------------------------------------------*/
307:
308: OSStatus GetNewNode (BTreeControlBlockPtr btreePtr,
309: UInt32 nodeNum,
310: NodeRec *returnNodePtr )
311: {
312: OSStatus err;
313: NodeDescPtr node;
314: void *pos;
315: GetBlockProcPtr getNodeProc;
316:
317:
318: //////////////////////// get buffer for new node ////////////////////////////
319:
320: returnNodePtr->blockSize = btreePtr->nodeSize; // indicate the size of a node
321:
322: getNodeProc = btreePtr->getBlockProc;
323: err = getNodeProc (btreePtr->fileRefNum,
324: nodeNum,
325: kGetBlock+kGetEmptyBlock,
326: returnNodePtr );
327:
328: if (err != noErr)
329: {
330: Panic ("\pGetNewNode: getNodeProc returned error.");
331: // returnNodePtr->buffer = nil;
332: return err;
333: }
334: ++btreePtr->numGetNewNodes;
335:
336:
337: ////////////////////////// initialize the node //////////////////////////////
338:
339: node = returnNodePtr->buffer;
340:
341: ClearNode (btreePtr, node); // clear the node
342:
343: pos = (char *)node + btreePtr->nodeSize - 2; // find address of last offset
344: *(UInt16 *)pos = sizeof (BTNodeDescriptor); // set offset to beginning of free space
345:
346:
347: return noErr;
348: }
349:
350:
351:
352: /*-------------------------------------------------------------------------------
353:
354: Routine: ReleaseNode - Call FS Agent to release node obtained by GetNode.
355:
356: Function: Informs the FS Agent that a BTree node may be released.
357:
358: Input: btreePtr - pointer to BTree control block
359: nodeNum - number of node to release
360:
361: Result: noErr - success
362: != noErr - failure
363: -------------------------------------------------------------------------------*/
364:
365: OSStatus ReleaseNode (BTreeControlBlockPtr btreePtr,
366: NodePtr nodePtr )
367: {
368: OSStatus err;
369: ReleaseBlockProcPtr releaseNodeProc;
370:
371:
372: LogStartTime(kTraceReleaseNode);
373:
374: err = noErr;
375:
376: if (nodePtr->buffer != nil)
377: {
378: releaseNodeProc = btreePtr->releaseBlockProc;
379: err = releaseNodeProc (btreePtr->fileRefNum,
380: nodePtr,
381: kReleaseBlock );
382: PanicIf (err, "\pReleaseNode: releaseNodeProc returned error.");
383: ++btreePtr->numReleaseNodes;
384: }
385:
386: nodePtr->buffer = nil;
387: nodePtr->blockHeader = nil;
388:
389: LogEndTime(kTraceReleaseNode, err);
390:
391: return err;
392: }
393:
394:
395:
396: /*-------------------------------------------------------------------------------
397:
398: Routine: UpdateNode - Mark a node as dirty and call FS Agent to release it.
399:
400: Function: Marks a BTree node dirty and informs the FS Agent that it may be released.
401:
402: //�� have another routine that clears & writes a node, so we can call
403: CheckNode from this routine.
404:
405: Input: btreePtr - pointer to BTree control block
406: nodeNum - number of node to release
407: transactionID - ID of transaction this node update is a part of
408: flags - special flags to pass to ReleaseNodeProc
409:
410: Result: noErr - success
411: != noErr - failure
412: -------------------------------------------------------------------------------*/
413:
414: OSStatus UpdateNode (BTreeControlBlockPtr btreePtr,
415: NodePtr nodePtr,
416: UInt32 transactionID,
417: UInt32 flags )
418: {
419: OSStatus err;
420: ReleaseBlockProcPtr releaseNodeProc;
421:
422:
423: err = noErr;
424:
425: if (nodePtr->buffer != nil) //�� why call UpdateNode if nil ?!?
426: {
427: if (DEBUG_BUILD)
428: {
429: if ( btreePtr->attributes & kBTVariableIndexKeysMask )
430: (void) CheckNode (btreePtr, nodePtr->buffer);
431: }
432:
433: LogStartTime(kTraceReleaseNode);
434:
435: releaseNodeProc = btreePtr->releaseBlockProc;
436: err = releaseNodeProc (btreePtr->fileRefNum,
437: nodePtr,
438: flags | kMarkBlockDirty );
439:
440: LogEndTime(kTraceReleaseNode, err);
441:
442: M_ExitOnError (err);
443: ++btreePtr->numUpdateNodes;
444: }
445:
446: nodePtr->buffer = nil;
447: nodePtr->blockHeader = nil;
448:
449: return noErr;
450:
451: ErrorExit:
452:
453: return err;
454: }
455:
456:
457:
458: /*-------------------------------------------------------------------------------
459:
460: Routine: CheckNode - Checks the validity of a node.
461:
462: Function: Checks the validity of a node by verifying that the fLink and bLink fields
463: are within the forks EOF. The node type must be one of the four known
464: types. The node height must be less than or equal to the tree height. The
465: node must not have more than the maximum number of records, and the record
466: offsets must make sense.
467:
468: Input: btreePtr - pointer to BTree control block
469: node - pointer to node to check
470:
471: Result: noErr - success
472: fsBTInvalidNodeErr - failure
473: -------------------------------------------------------------------------------*/
474:
475: OSStatus CheckNode (BTreeControlBlockPtr btreePtr, NodeDescPtr node )
476: {
477: SInt32 index;
478: SInt32 maxRecords;
479: UInt32 maxNode;
480: UInt16 nodeSize;
481: UInt16 offset;
482: UInt16 prevOffset;
483:
484: nodeSize = btreePtr->nodeSize;
485:
486: ///////////////////// are fLink and bLink within EOF ////////////////////////
487:
488: maxNode = (GetFileControlBlock(btreePtr->fileRefNum)->fcbEOF / nodeSize) - 1;
489:
490: if ( (node->fLink > maxNode) || (node->bLink > maxNode) )
491: return fsBTInvalidNodeErr;
492:
493: /////////////// check node type (leaf, index, header, map) //////////////////
494:
495: if ( (node->kind < kBTLeafNode) || (node->kind > kBTMapNode) )
496: return fsBTInvalidNodeErr;
497:
498: ///////////////////// is node height > tree depth? //////////////////////////
499:
500: if ( node->height > btreePtr->treeDepth )
501: return fsBTInvalidNodeErr;
502:
503: //////////////////////// check number of records ////////////////////////////
504:
505: //XXX can we calculate a more accurate minimum record size?
506: maxRecords = ( nodeSize - sizeof (BTNodeDescriptor) ) >> 3;
507:
508: if (node->numRecords > maxRecords)
509: return fsBTInvalidNodeErr;
510:
511: ////////////////////////// check record offsets /////////////////////////////
512:
513: index = node->numRecords; /* start index at free space */
514: prevOffset = nodeSize - (index << 1); /* use 2 bytes past end of free space */
515:
516: do {
517: offset = GetRecordOffset (btreePtr, node, index);
518:
519: if (offset & 1) // offset is odd
520: return fsBTInvalidNodeErr;
521:
522: if (offset >= prevOffset) // offset >= previous offset
523: return fsBTInvalidNodeErr;
524:
525: /* reject keys that overflow record slot */
526: if ((node->kind == kBTLeafNode) &&
527: (index < node->numRecords) && /* ignore free space record */
528: (CalcKeySize(btreePtr, (KeyPtr) ((Ptr)node + offset)) > (prevOffset - offset))) {
529: return fsBTInvalidNodeErr;
530: }
531:
532: prevOffset = offset;
533: } while ( --index >= 0 );
534:
535: if (offset < sizeof (BTNodeDescriptor) ) // first offset < minimum ?
536: return fsBTInvalidNodeErr;
537:
538: return noErr;
539: }
540:
541:
542: #if HFS_DIAGNOSTIC
543: static void PrintNode(const NodeDescPtr node, UInt16 nodeSize, UInt32 nodeNumber)
544: {
545: struct row {
546: UInt16 word[8];
547: };
548: struct row *offset;
549: UInt16 rows;
550: UInt32 *lp;
551:
552: PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber, nodeNumber);
553:
554: rows = nodeSize/16;
555: lp = (UInt32*) node;
556: offset = 0;
557:
558: while (rows-- > 0)
559: PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int)offset++, *lp++, *lp++, *lp++, *lp++);
560: }
561: #endif
562:
563:
564: /*-------------------------------------------------------------------------------
565:
566: Routine: ClearNode - Clear a node to all zeroes.
567:
568: Function: Writes zeroes from beginning of node for nodeSize bytes.
569:
570: Input: btreePtr - pointer to BTree control block
571: node - pointer to node to clear
572:
573: Result: none
574: -------------------------------------------------------------------------------*/
575:
576: void ClearNode (BTreeControlBlockPtr btreePtr, NodeDescPtr node )
577: {
578: ClearMemory( node, btreePtr->nodeSize );
579: }
580:
581: /*-------------------------------------------------------------------------------
582:
583: Routine: InsertRecord - Inserts a record into a BTree node.
584:
585: Function:
586:
587: Note: Record size must be even!
588:
589: Input: btreePtr - pointer to BTree control block
590: node - pointer to node to insert the record
591: index - position record is to be inserted
592: recPtr - pointer to record to insert
593:
594: Result: noErr - success
595: fsBTFullErr - record larger than remaining free space.
596: -------------------------------------------------------------------------------*/
597:
598: Boolean InsertRecord (BTreeControlBlockPtr btreePtr,
599: NodeDescPtr node,
600: UInt16 index,
601: RecordPtr recPtr,
602: UInt16 recSize )
603: {
604: UInt16 freeSpace;
605: UInt16 indexOffset;
606: UInt16 freeOffset;
607: UInt16 bytesToMove;
608: void *src;
609: void *dst;
610:
611: //// will new record fit in node?
612:
613: freeSpace = GetNodeFreeSize (btreePtr, node);
614: //�� we could get freeOffset & calc freeSpace
615: if ( freeSpace < recSize + 2)
616: {
617: return false;
618: }
619:
620:
621: //// make hole for new record
622:
623: indexOffset = GetRecordOffset (btreePtr, node, index);
624: freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);
625:
626: src = ((Ptr) node) + indexOffset;
627: dst = ((Ptr) src) + recSize;
628: bytesToMove = freeOffset - indexOffset;
629: MoveRecordsRight (src, dst, bytesToMove);
630:
631:
632: //// adjust offsets for moved records
633:
634: InsertOffset (btreePtr, node, index, recSize);
635:
636:
637: //// move in the new record
638:
639: dst = ((Ptr) node) + indexOffset;
640: MoveRecordsLeft (recPtr, dst, recSize);
641:
642: return true;
643: }
644:
645:
646:
647: /*-------------------------------------------------------------------------------
648:
649: Routine: InsertKeyRecord - Inserts a record into a BTree node.
650:
651: Function:
652:
653: Note: Record size must be even!
654:
655: Input: btreePtr - pointer to BTree control block
656: node - pointer to node to insert the record
657: index - position record is to be inserted
658: keyPtr - pointer to key for record to insert
659: keyLength - length of key (or maxKeyLength)
660: recPtr - pointer to record to insert
661: recSize - number of bytes to copy for record
662:
663: Result: noErr - success
664: fsBTFullErr - record larger than remaining free space.
665: -------------------------------------------------------------------------------*/
666:
667: Boolean InsertKeyRecord (BTreeControlBlockPtr btreePtr,
668: NodeDescPtr node,
669: UInt16 index,
670: KeyPtr keyPtr,
671: UInt16 keyLength,
672: RecordPtr recPtr,
673: UInt16 recSize )
674: {
675: UInt16 freeSpace;
676: UInt16 indexOffset;
677: UInt16 freeOffset;
678: UInt16 bytesToMove;
679: UInt8 * src;
680: UInt8 * dst;
681: UInt16 keySize;
682: UInt16 rawKeyLength;
683: UInt16 sizeOfLength;
684:
685: //// calculate actual key size
686:
687: if ( btreePtr->attributes & kBTBigKeysMask )
688: keySize = keyLength + sizeof(UInt16);
689: else
690: keySize = keyLength + sizeof(UInt8);
691:
692: if ( M_IsOdd (keySize) )
693: ++keySize; // add pad byte
694:
695:
696: //// will new record fit in node?
697:
698: freeSpace = GetNodeFreeSize (btreePtr, node);
699: //�� we could get freeOffset & calc freeSpace
700: if ( freeSpace < keySize + recSize + 2)
701: {
702: return false;
703: }
704:
705:
706: //// make hole for new record
707:
708: indexOffset = GetRecordOffset (btreePtr, node, index);
709: freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);
710:
711: src = ((UInt8 *) node) + indexOffset;
712: dst = ((UInt8 *) src) + keySize + recSize;
713: bytesToMove = freeOffset - indexOffset;
714: MoveRecordsRight (src, dst, bytesToMove);
715:
716:
717: //// adjust offsets for moved records
718:
719: InsertOffset (btreePtr, node, index, keySize + recSize);
720:
721:
722: //// copy record key
723:
724: dst = ((UInt8 *) node) + indexOffset;
725:
726: if ( btreePtr->attributes & kBTBigKeysMask )
727: {
728: *((UInt16*) dst)++ = keyLength; // use keyLength rather than key.length
729: rawKeyLength = keyPtr->length16;
730: sizeOfLength = 2;
731: }
732: else
733: {
734: *dst++ = keyLength; // use keyLength rather than key.length
735: rawKeyLength = keyPtr->length8;
736: sizeOfLength = 1;
737: }
738:
739: MoveRecordsLeft ( ((UInt8 *) keyPtr) + sizeOfLength, dst, rawKeyLength); // copy key
740:
741: // any pad bytes?
742: bytesToMove = keySize - rawKeyLength;
743: if (bytesToMove)
744: ClearMemory (dst + rawKeyLength, bytesToMove); // clear pad bytes in index key
745:
746:
747: //// copy record data
748:
749: dst = ((UInt8 *) node) + indexOffset + keySize;
750: MoveRecordsLeft (recPtr, dst, recSize);
751:
752: return true;
753: }
754:
755:
756:
757: /*-------------------------------------------------------------------------------
758:
759: Routine: DeleteRecord - Deletes a record from a BTree node.
760:
761: Function:
762:
763: Input: btreePtr - pointer to BTree control block
764: node - pointer to node to insert the record
765: index - position record is to be inserted
766:
767: Result: none
768: -------------------------------------------------------------------------------*/
769:
770: void DeleteRecord (BTreeControlBlockPtr btreePtr,
771: NodeDescPtr node,
772: UInt16 index )
773: {
774: SInt16 indexOffset;
775: SInt16 nextOffset;
776: SInt16 freeOffset;
777: SInt16 bytesToMove;
778: void *src;
779: void *dst;
780:
781: //// compress records
782: indexOffset = GetRecordOffset (btreePtr, node, index);
783: nextOffset = GetRecordOffset (btreePtr, node, index + 1);
784: freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);
785:
786: src = ((Ptr) node) + nextOffset;
787: dst = ((Ptr) node) + indexOffset;
788: bytesToMove = freeOffset - nextOffset;
789: MoveRecordsLeft (src, dst, bytesToMove);
790:
791: //// Adjust the offsets
792: DeleteOffset (btreePtr, node, index);
793:
794: /* clear out new free space */
795: bytesToMove = nextOffset - indexOffset;
796: ClearMemory(GetRecordAddress(btreePtr, node, node->numRecords), bytesToMove);
797:
798: }
799:
800:
801:
802: /*-------------------------------------------------------------------------------
803:
804: Routine: SearchNode - Return index for record that matches key.
805:
806: Function: Returns the record index for the record that matches the search key.
807: If no record was found that matches the search key, the "insert index"
808: of where the record should go is returned instead.
809:
810: Algorithm: A binary search algorithm is used to find the specified key.
811:
812: Input: btreePtr - pointer to BTree control block
813: node - pointer to node that contains the record
814: searchKey - pointer to the key to match
815:
816: Output: index - pointer to beginning of key for record
817:
818: Result: true - success (index = record index)
819: false - key did not match anything in node (index = insert index)
820: -------------------------------------------------------------------------------*/
821: Boolean
822: SearchNode( BTreeControlBlockPtr btreePtr,
823: NodeDescPtr node,
824: KeyPtr searchKey,
825: UInt16 *returnIndex )
826: {
827: SInt32 lowerBound;
828: SInt32 upperBound;
829: SInt32 index;
830: SInt32 result;
831: KeyPtr trialKey;
832: UInt16 *offset;
833: KeyCompareProcPtr compareProc = btreePtr->keyCompareProc;
834:
835: lowerBound = 0;
836: upperBound = node->numRecords - 1;
837: offset = (UInt16 *) ((UInt8 *)(node) + (btreePtr)->nodeSize - kOffsetSize);
838:
839: while (lowerBound <= upperBound) {
840: index = (lowerBound + upperBound) >> 1;
841:
842: trialKey = (KeyPtr) ((UInt8 *)node + *(offset - index));
843:
844: result = compareProc(searchKey, trialKey);
845:
846: if (result < 0) {
847: upperBound = index - 1; /* search < trial */
848: } else if (result > 0) {
849: lowerBound = index + 1; /* search > trial */
850: } else {
851: *returnIndex = index; /* search == trial */
852: return true;
853: }
854: }
855:
856: *returnIndex = lowerBound; /* lowerBound is insert index */
857: return false;
858: }
859:
860:
861: /*-------------------------------------------------------------------------------
862:
863: Routine: GetRecordByIndex - Return pointer to key and data, and size of data.
864:
865: Function: Returns a pointer to beginning of key for record, a pointer to the
866: beginning of the data for the record, and the size of the record data
867: (does not include the size of the key).
868:
869: Input: btreePtr - pointer to BTree control block
870: node - pointer to node that contains the record
871: index - index of record to get
872:
873: Output: keyPtr - pointer to beginning of key for record
874: dataPtr - pointer to beginning of data for record
875: dataSize - size of the data portion of the record
876:
877: Result: none
878: -------------------------------------------------------------------------------*/
879:
880: OSStatus GetRecordByIndex (BTreeControlBlockPtr btreePtr,
881: NodeDescPtr node,
882: UInt16 index,
883: KeyPtr *keyPtr,
884: UInt8 * *dataPtr,
885: UInt16 *dataSize )
886: {
887: UInt16 offset;
888: UInt16 nextOffset;
889: UInt16 keySize;
890:
891: //
892: // Make sure index is valid (in range 0..numRecords-1)
893: //
894: if (index >= node->numRecords)
895: return fsBTRecordNotFoundErr;
896:
897: //// find keyPtr
898: offset = GetRecordOffset (btreePtr, node, index);
899: *keyPtr = (KeyPtr) ((Ptr)node + offset);
900:
901: //// find dataPtr
902: keySize = CalcKeySize(btreePtr, *keyPtr);
903: if ( M_IsOdd (keySize) )
904: ++keySize; // add pad byte
905:
906: offset += keySize; // add the key length to find data offset
907: *dataPtr = (UInt8 *) node + offset;
908:
909: //// find dataSize
910: nextOffset = GetRecordOffset (btreePtr, node, index + 1);
911: *dataSize = nextOffset - offset;
912:
913: return noErr;
914: }
915:
916:
917:
918: /*-------------------------------------------------------------------------------
919:
920: Routine: GetNodeDataSize - Return the amount of space used for data in the node.
921:
922: Function: Gets the size of the data currently contained in a node, excluding
923: the node header. (record data + offset overhead)
924:
925: Input: btreePtr - pointer to BTree control block
926: node - pointer to node that contains the record
927:
928: Result: - number of bytes used for data and offsets in the node.
929: -------------------------------------------------------------------------------*/
930:
931: UInt16 GetNodeDataSize (BTreeControlBlockPtr btreePtr, NodeDescPtr node )
932: {
933: UInt16 freeOffset;
934:
935: freeOffset = GetRecordOffset (btreePtr, node, node->numRecords);
936:
937: return freeOffset + (node->numRecords << 1) - sizeof (BTNodeDescriptor);
938: }
939:
940:
941:
942: /*-------------------------------------------------------------------------------
943:
944: Routine: GetNodeFreeSize - Return the amount of free space in the node.
945:
946: Function:
947:
948: Input: btreePtr - pointer to BTree control block
949: node - pointer to node that contains the record
950:
951: Result: - number of bytes of free space in the node.
952: -------------------------------------------------------------------------------*/
953:
954: UInt16 GetNodeFreeSize (BTreeControlBlockPtr btreePtr, NodeDescPtr node )
955: {
956: UInt16 freeOffset;
957:
958: freeOffset = GetRecordOffset (btreePtr, node, node->numRecords); //�� inline?
959:
960: return btreePtr->nodeSize - freeOffset - (node->numRecords << 1) - kOffsetSize;
961: }
962:
963:
964:
965: /*-------------------------------------------------------------------------------
966:
967: Routine: GetRecordOffset - Return the offset for record "index".
968:
969: Function:
970:
971: Input: btreePtr - pointer to BTree control block
972: node - pointer to node that contains the record
973: index - record to obtain offset for
974:
975: Result: - offset (in bytes) from beginning of node of record specified by index
976: -------------------------------------------------------------------------------*/
977: // make this a macro (for inlining)
978: #if 0
979: UInt16 GetRecordOffset (BTreeControlBlockPtr btreePtr,
980: NodeDescPtr node,
981: UInt16 index )
982: {
983: void *pos;
984:
985:
986: pos = (UInt8 *)node + btreePtr->nodeSize - (index << 1) - kOffsetSize;
987:
988: return *(short *)pos;
989: }
990: #endif
991:
992:
993:
994: /*-------------------------------------------------------------------------------
995:
996: Routine: GetRecordAddress - Return address of record "index".
997:
998: Function:
999:
1000: Input: btreePtr - pointer to BTree control block
1001: node - pointer to node that contains the record
1002: index - record to obtain offset address for
1003:
1004: Result: - pointer to record "index".
1005: -------------------------------------------------------------------------------*/
1006: // make this a macro (for inlining)
1007: #if 0
1008: UInt8 * GetRecordAddress (BTreeControlBlockPtr btreePtr,
1009: NodeDescPtr node,
1010: UInt16 index )
1011: {
1012: UInt8 * pos;
1013:
1014: pos = (UInt8 *)node + GetRecordOffset (btreePtr, node, index);
1015:
1016: return pos;
1017: }
1018: #endif
1019:
1020:
1021:
1022: /*-------------------------------------------------------------------------------
1023:
1024: Routine: GetRecordSize - Return size of record "index".
1025:
1026: Function:
1027:
1028: Note: This does not work on the FreeSpace index!
1029:
1030: Input: btreePtr - pointer to BTree control block
1031: node - pointer to node that contains the record
1032: index - record to obtain record size for
1033:
1034: Result: - size of record "index".
1035: -------------------------------------------------------------------------------*/
1036:
1037: UInt16 GetRecordSize (BTreeControlBlockPtr btreePtr,
1038: NodeDescPtr node,
1039: UInt16 index )
1040: {
1041: UInt16 *pos;
1042:
1043: pos = (UInt16 *) ((Ptr)node + btreePtr->nodeSize - (index << 1) - kOffsetSize);
1044:
1045: return *(pos-1) - *pos;
1046: }
1047:
1048:
1049:
1050: /*-------------------------------------------------------------------------------
1051: Routine: GetOffsetAddress - Return address of offset for record "index".
1052:
1053: Function:
1054:
1055: Input: btreePtr - pointer to BTree control block
1056: node - pointer to node that contains the record
1057: index - record to obtain offset address for
1058:
1059: Result: - pointer to offset for record "index".
1060: -------------------------------------------------------------------------------*/
1061:
1062: UInt16 *GetOffsetAddress (BTreeControlBlockPtr btreePtr,
1063: NodeDescPtr node,
1064: UInt16 index )
1065: {
1066: void *pos;
1067:
1068: pos = (Ptr)node + btreePtr->nodeSize - (index << 1) -2;
1069:
1070: return (UInt16 *)pos;
1071: }
1072:
1073:
1074:
1075: /*-------------------------------------------------------------------------------
1076: Routine: GetChildNodeNum - Return child node number from index record "index".
1077:
1078: Function: Returns the first UInt32 stored after the key for record "index".
1079:
1080: Assumes: The node is an Index Node.
1081: The key.length stored at record "index" is ODD. //�� change for variable length index keys
1082:
1083: Input: btreePtr - pointer to BTree control block
1084: node - pointer to node that contains the record
1085: index - record to obtain child node number from
1086:
1087: Result: - child node number from record "index".
1088: -------------------------------------------------------------------------------*/
1089:
1090: UInt32 GetChildNodeNum (BTreeControlBlockPtr btreePtr,
1091: NodeDescPtr nodePtr,
1092: UInt16 index )
1093: {
1094: UInt8 * pos;
1095:
1096: pos = GetRecordAddress (btreePtr, nodePtr, index);
1097: pos += CalcKeySize(btreePtr, (BTreeKey *) pos); // key.length + size of length field
1098:
1099: return *(UInt32 *)pos;
1100: }
1101:
1102:
1103:
1104: /*-------------------------------------------------------------------------------
1105: Routine: InsertOffset - Add an offset and adjust existing offsets by delta.
1106:
1107: Function: Add an offset at 'index' by shifting 'index+1' through the last offset
1108: and adjusting them by 'delta', the size of the record to be inserted.
1109: The number of records contained in the node is also incremented.
1110:
1111: Input: btreePtr - pointer to BTree control block
1112: node - pointer to node
1113: index - index at which to insert record
1114: delta - size of record to be inserted
1115:
1116: Result: none
1117: -------------------------------------------------------------------------------*/
1118:
1119: void InsertOffset (BTreeControlBlockPtr btreePtr,
1120: NodeDescPtr node,
1121: UInt16 index,
1122: UInt16 delta )
1123: {
1124: UInt16 *src, *dst;
1125: UInt16 numOffsets;
1126:
1127: src = GetOffsetAddress (btreePtr, node, node->numRecords); // point to free offset
1128: dst = src - 1; // point to new offset
1129: numOffsets = node->numRecords++ - index; // subtract index & postincrement
1130:
1131: do {
1132: *dst++ = *src++ + delta; // to tricky?
1133: } while (numOffsets--);
1134: }
1135:
1136:
1137:
1138: /*-------------------------------------------------------------------------------
1139:
1140: Routine: DeleteOffset - Delete an offset.
1141:
1142: Function: Delete the offset at 'index' by shifting 'index+1' through the last offset
1143: and adjusting them by the size of the record 'index'.
1144: The number of records contained in the node is also decremented.
1145:
1146: Input: btreePtr - pointer to BTree control block
1147: node - pointer to node
1148: index - index at which to delete record
1149:
1150: Result: none
1151: -------------------------------------------------------------------------------*/
1152:
1153: void DeleteOffset (BTreeControlBlockPtr btreePtr,
1154: NodeDescPtr node,
1155: UInt16 index )
1156: {
1157: UInt16 *src, *dst;
1158: UInt16 numOffsets;
1159: UInt16 delta;
1160:
1161: dst = GetOffsetAddress (btreePtr, node, index);
1162: src = dst - 1;
1163: delta = *src - *dst;
1164: numOffsets = --node->numRecords - index; // predecrement numRecords & subtract index
1165:
1166: while (numOffsets--)
1167: {
1168: *--dst = *--src - delta; // work our way left
1169: }
1170: }
1171:
1172:
1173:
1174: /*-------------------------------------------------------------------------------
1175:
1176: Routine: MoveRecordsLeft - Move records left within a node.
1177:
1178: Function: Moves a number of bytes from src to dst. Safely handles overlapping
1179: ranges if the bytes are being moved to the "left". No bytes are moved
1180: if bytesToMove is zero.
1181:
1182: Input: src - pointer to source
1183: dst - pointer to destination
1184: bytesToMove - number of bytes to move records
1185:
1186: Result: none
1187: -------------------------------------------------------------------------------*/
1188: #if BCOPY_BROKEN
1189: void MoveRecordsLeft (UInt8 * src,
1190: UInt8 * dst,
1191: UInt16 bytesToMove )
1192: {
1193: while (bytesToMove--)
1194: *dst++ = *src++;
1195: }
1196: #endif
1197:
1198:
1199: /*-------------------------------------------------------------------------------
1200:
1201: Routine: MoveRecordsRight - Move records right within a node.
1202:
1203: Function: Moves a number of bytes from src to dst. Safely handles overlapping
1204: ranges if the bytes are being moved to the "right". No bytes are moved
1205: if bytesToMove is zero.
1206:
1207: Input: src - pointer to source
1208: dst - pointer to destination
1209: bytesToMove - number of bytes to move records
1210:
1211: Result: none
1212: -------------------------------------------------------------------------------*/
1213: #if BCOPY_BROKEN
1214: void MoveRecordsRight (UInt8 * src,
1215: UInt8 * dst,
1216: UInt16 bytesToMove )
1217: {
1218: src += bytesToMove;
1219: dst += bytesToMove;
1220:
1221: while (bytesToMove--)
1222: *--dst = *--src;
1223: }
1224: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.