|
|
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: BTreeMiscOps.c
27:
28: Contains: Miscellaneous 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-1997 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: (DSH) Deric Horn
47: (msd) Mark Day
48: (djb) Don Brady
49:
50: Change History (most recent first):
51:
52: <CS2> 9/4/97 djb Optimize TrySimpleReplace for the case where record size is not
53: changing.
54: <CS1> 4/23/97 djb first checked in
55:
56: <HFS7> 3/31/97 djb Move ClearMemory to Utilities.c.
57: <HFS6> 3/17/97 DSH Casting for DFA
58: <HFS5> 2/27/97 msd Remove temporary fix from last revision. BTree EOF's should be
59: correct now, so check for strict equality.
60: <HFS4> 2/26/97 msd Fix a casting problem in ClearMemory. TEMPORARY FIX: Made
61: VerifyHeader more lenient, allowing the EOF to be greater than
62: the amount actually used by nodes; this should really be fixed
63: in the formatting code (which needs to compute the real BTree
64: sizes before writing the volume header).
65: <HFS3> 2/19/97 djb Added ClearMemory. Changed CalcKeyLength to KeyLength.
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: <9> 10/25/96 ser Changing for new VFPI
72: <8> 10/18/96 ser Converting over VFPI changes
73: <7> 9/17/96 dkh More BTree statistics. Change IsItAHint to not always check to
74: see if the hint node is allocated.
75: <6> 9/16/96 dkh Revised BTree statistics.
76: <5> 6/20/96 dkh Radar #1358740. Change from using Pools to debug MemAllocators.
77: <4> 1/22/96 dkh Change Pools.i inclusion to PoolsPriv.i
78: <3> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
79: <2> 12/7/95 dkh D10E2 build. Changed usage of Ref data type to LogicalAddress.
80: <1> 10/18/95 rst Moved from Scarecrow project.
81:
82: <19> 4/26/95 prp In UpdateHeader, clear the dirty flag after the BTree is updated.
83: <18> 1/12/95 wjk Adopt Model FileSystem changes in D5.
84: <17> 11/16/94 prp Add IsItAHint routine and use it whenever hint's node number was
85: used for testing.
86: <16> 10/5/94 bk add pools.h include file
87: <15> 9/30/94 prp Get in sync with D2 interface changes.
88: <14> 7/22/94 wjk Convert to the new set of header files.
89: <13> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
90: NRCmds environments.
91: <12> 11/30/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
92: NRCmds environments.
93: <11> 11/23/93 wjk Changes required to compile on the RS6000.
94: <10> 8/31/93 prp Use U64SetU instead of S64Set.
95: <9> 6/2/93 gs Update for changes to FSErrors.h and add some comments.
96: <8> 5/21/93 gs Modify UpdateHeader to write out attributes. Remove
97: Get/UpdateNode from TrySimpleReplace.
98: <7> 5/10/93 gs Add TrySimpleReplace routine.
99: <6> 3/23/93 gs Change MoveData to take void * instead of Ptr. Add UpdateHeader
100: and ClearBytes routines.
101: <5> 2/8/93 gs Add FindIteratorPosition.
102: <4> 12/10/92 gs Implement CheckKeyDescriptor and the KeyDescriptor interpreter.
103: <3> 12/8/92 gs Add GetKeyDescriptor, VerifyHeader, and Alloc/Dealloc memory
104: routines.
105: <2> 12/2/92 gs Add CompareKeys routine.
106: <1> 11/15/92 gs first checked in
107:
108: */
109:
110: #include "../headers/BTreesPrivate.h"
111:
112:
113: ////////////////////////////// Routine Definitions //////////////////////////////
114:
115: /*-------------------------------------------------------------------------------
116: Routine: CalcKeyRecordSize - Return size of combined key/record structure.
117:
118: Function: Rounds keySize and recSize so they will end on word boundaries.
119: Does NOT add size of offset.
120:
121: Input: keySize - length of key (including length field)
122: recSize - length of record data
123:
124: Output: none
125:
126: Result: UInt16 - size of combined key/record that will be inserted in btree
127: -------------------------------------------------------------------------------*/
128:
129: UInt16 CalcKeyRecordSize (UInt16 keySize,
130: UInt16 recSize )
131: {
132: if ( M_IsOdd (keySize) ) keySize += 1; // pad byte
133:
134: if (M_IsOdd (recSize) ) recSize += 1; // pad byte
135:
136: return (keySize + recSize);
137: }
138:
139:
140:
141: /*-------------------------------------------------------------------------------
142: Routine: VerifyHeader - Validate fields of the BTree header record.
143:
144: Function: Examines the fields of the BTree header record to determine if the
145: fork appears to contain a valid BTree.
146:
147: Input: forkPtr - pointer to fork control block
148: header - pointer to BTree header
149:
150:
151: Result: noErr - success
152: != noErr - failure
153: -------------------------------------------------------------------------------*/
154:
155: OSStatus VerifyHeader (FCB *filePtr,
156: HeaderPtr header )
157: {
158: UInt32 forkSize;
159: UInt32 totalNodes;
160:
161:
162: switch (header->nodeSize) // node size == 512*2^n
163: {
164: case 512:
165: case 1024:
166: case 2048:
167: case 4096:
168: case 8192:
169: case 16384:
170: case 32768: break;
171: default: return fsBTInvalidHeaderErr; //�� E_BadNodeType
172: }
173:
174: totalNodes = header->totalNodes;
175:
176: forkSize = totalNodes * header->nodeSize;
177:
178: if ( forkSize != filePtr->fcbEOF )
179: return fsBTInvalidHeaderErr;
180:
181: if ( header->freeNodes >= totalNodes )
182: return fsBTInvalidHeaderErr;
183:
184: if ( header->rootNode >= totalNodes )
185: return fsBTInvalidHeaderErr;
186:
187: if ( header->firstLeafNode >= totalNodes )
188: return fsBTInvalidHeaderErr;
189:
190: if ( header->lastLeafNode >= totalNodes )
191: return fsBTInvalidHeaderErr;
192:
193: if ( header->treeDepth > kMaxTreeDepth )
194: return fsBTInvalidHeaderErr;
195:
196:
197: /////////////////////////// Check BTree Type ////////////////////////////////
198:
199: switch (header->btreeType)
200: {
201: case 0: // HFS Type - no Key Descriptor
202: case kUserBTreeType: // with Key Descriptors etc.
203: case kReservedBTreeType: // Desktop Mgr BTree ?
204: break;
205:
206: default: return fsBTUnknownVersionErr;
207: }
208:
209: return noErr;
210: }
211:
212:
213:
214: /*-------------------------------------------------------------------------------
215: Routine: UpdateHeader - Write BTreeInfoRec fields to Header node.
216:
217: Function: Checks the kBTHeaderDirty flag in the BTreeInfoRec and updates the
218: header node if necessary.
219:
220: Input: btreePtr - pointer to BTreeInfoRec
221:
222:
223: Result: noErr - success
224: != noErr - failure
225: -------------------------------------------------------------------------------*/
226:
227: OSStatus UpdateHeader (BTreeControlBlockPtr btreePtr)
228: {
229: OSStatus err;
230: BlockDescriptor node;
231: HeaderPtr header;
232:
233:
234: if ((btreePtr->flags & kBTHeaderDirty) == 0) // btree info already flushed
235: return noErr;
236:
237:
238: err = GetNode (btreePtr, kHeaderNodeNum, &node );
239: if (err != noErr)
240: return err;
241:
242: header = node.buffer;
243:
244: header->treeDepth = btreePtr->treeDepth;
245: header->rootNode = btreePtr->rootNode;
246: header->leafRecords = btreePtr->leafRecords;
247: header->firstLeafNode = btreePtr->firstLeafNode;
248: header->lastLeafNode = btreePtr->lastLeafNode;
249: header->nodeSize = btreePtr->nodeSize; //�� this shouldn't change
250: header->maxKeyLength = btreePtr->maxKeyLength; //�� neither should this
251: header->totalNodes = btreePtr->totalNodes;
252: header->freeNodes = btreePtr->freeNodes;
253: header->btreeType = btreePtr->btreeType;
254:
255: // ignore header->clumpSize; //�� rename this field?
256:
257: err = UpdateNode (btreePtr, &node);
258:
259: btreePtr->flags &= (~kBTHeaderDirty);
260:
261: return err;
262: }
263:
264:
265:
266: /*-------------------------------------------------------------------------------
267: Routine: FindIteratorPosition - One_line_description.
268:
269: Function: Brief_description_of_the_function_and_any_side_effects
270:
271: Algorithm: see FSC.BT.BTIterateRecord.PICT
272:
273: Note: //�� document side-effects of bad node hints
274:
275: Input: btreePtr - description
276: iterator - description
277:
278:
279: Output: iterator - description
280: left - description
281: middle - description
282: right - description
283: nodeNum - description
284: returnIndex - description
285: foundRecord - description
286:
287:
288: Result: noErr - success
289: != noErr - failure
290: -------------------------------------------------------------------------------*/
291:
292: OSStatus FindIteratorPosition (BTreeControlBlockPtr btreePtr,
293: BTreeIteratorPtr iterator,
294: BlockDescriptor *left,
295: BlockDescriptor *middle,
296: BlockDescriptor *right,
297: UInt32 *returnNodeNum,
298: UInt16 *returnIndex,
299: Boolean *foundRecord )
300: {
301: OSStatus err;
302: Boolean foundIt;
303: UInt32 nodeNum;
304: UInt16 leftIndex, index, rightIndex;
305: Boolean validHint;
306:
307: // assume btreePtr valid
308: // assume left, middle, right point to BlockDescriptors
309: // assume nodeNum points to UInt32
310: // assume index points to UInt16
311: // assume foundRecord points to Boolean
312:
313: left->buffer = nil;
314: middle->buffer = nil;
315: right->buffer = nil;
316:
317: foundIt = false;
318:
319: if (iterator == nil) // do we have an iterator?
320: {
321: err = fsBTInvalidIteratorErr;
322: goto ErrorExit;
323: }
324:
325: #if SupportsKeyDescriptors
326: //�� verify iterator key (change CheckKey to take btreePtr instead of keyDescPtr?)
327: if (btreePtr->keyDescPtr != nil)
328: {
329: err = CheckKey (&iterator->key, btreePtr->keyDescPtr, btreePtr->maxKeyLength );
330: M_ExitOnError (err);
331: }
332: #endif
333:
334: err = IsItAHint (btreePtr, iterator, &validHint);
335: M_ExitOnError (err);
336:
337: nodeNum = iterator->hint.nodeNum;
338: if (! validHint) // does the hint appear to be valid?
339: {
340: goto SearchTheTree;
341: }
342:
343: err = GetNode (btreePtr, nodeNum, middle);
344: if( err == fsBTInvalidNodeErr ) // returned if nodeNum is out of range
345: goto SearchTheTree;
346:
347: M_ExitOnError (err);
348:
349: if ( ((NodeDescPtr) middle->buffer)->type != kLeafNode ||
350: ((NodeDescPtr) middle->buffer)->numRecords <= 0 )
351: {
352: goto SearchTheTree;
353: }
354:
355: ++btreePtr->numValidHints;
356:
357: foundIt = SearchNode (btreePtr, middle->buffer, &iterator->key, &index);
358: if (foundIt == true)
359: {
360: goto SuccessfulExit;
361: }
362:
363: if (index == 0)
364: {
365: if (((NodeDescPtr) middle->buffer)->bLink == 0) // before 1st btree record
366: {
367: goto SuccessfulExit;
368: }
369:
370: nodeNum = ((NodeDescPtr) middle->buffer)->bLink;
371:
372: err = GetLeftSiblingNode (btreePtr, middle->buffer, left);
373: M_ExitOnError (err);
374:
375: if ( ((NodeDescPtr) left->buffer)->type != kLeafNode ||
376: ((NodeDescPtr) left->buffer)->numRecords <= 0 )
377: {
378: goto SearchTheTree;
379: }
380:
381: foundIt = SearchNode (btreePtr, left->buffer, &iterator->key, &leftIndex);
382: if (foundIt == true)
383: {
384: *right = *middle;
385: *middle = *left;
386: left->buffer = nil;
387: index = leftIndex;
388:
389: goto SuccessfulExit;
390: }
391:
392: if (leftIndex == 0) // we're lost!
393: {
394: goto SearchTheTree;
395: }
396: else if (leftIndex >= ((NodeDescPtr) left->buffer)->numRecords)
397: {
398: nodeNum = ((NodeDescPtr) left->buffer)->fLink;
399:
400: PanicIf (index != 0, "\pFindIteratorPosition: index != 0"); //�� just checking...
401: goto SuccessfulExit;
402: }
403: else
404: {
405: *right = *middle;
406: *middle = *left;
407: left->buffer = nil;
408: index = leftIndex;
409:
410: goto SuccessfulExit;
411: }
412: }
413: else if (index >= ((NodeDescPtr) middle->buffer)->numRecords)
414: {
415: if (((NodeDescPtr) middle->buffer)->fLink == 0) // beyond last record
416: {
417: goto SuccessfulExit;
418: }
419:
420: nodeNum = ((NodeDescPtr) middle->buffer)->fLink;
421:
422: err = GetRightSiblingNode (btreePtr, middle->buffer, right);
423: M_ExitOnError (err);
424:
425: if ( ((NodeDescPtr) right->buffer)->type != kLeafNode ||
426: ((NodeDescPtr) right->buffer)->numRecords <= 0 )
427: {
428: goto SearchTheTree;
429: }
430:
431: foundIt = SearchNode (btreePtr, right->buffer, &iterator->key, &rightIndex);
432: if (rightIndex >= ((NodeDescPtr) right->buffer)->numRecords) // we're lost
433: {
434: goto SearchTheTree;
435: }
436: else // we found it, or rightIndex==0, or rightIndex<numRecs
437: {
438: *left = *middle;
439: *middle = *right;
440: right->buffer = nil;
441: index = rightIndex;
442:
443: goto SuccessfulExit;
444: }
445: }
446:
447:
448: //////////////////////////// Search The Tree ////////////////////////////////
449:
450: SearchTheTree:
451: {
452: TreePathTable treePathTable; // so we only use stack space if we need to
453:
454: err = ReleaseNode (btreePtr, left); M_ExitOnError (err);
455: err = ReleaseNode (btreePtr, middle); M_ExitOnError (err);
456: err = ReleaseNode (btreePtr, right); M_ExitOnError (err);
457:
458: err = SearchTree ( btreePtr, &iterator->key, treePathTable, &nodeNum, middle, &index);
459: switch (err) //�� separate find condition from exceptions
460: {
461: case noErr: foundIt = true; break;
462: case fsBTRecordNotFoundErr: break;
463: default: goto ErrorExit;
464: }
465: }
466:
467: /////////////////////////////// Success! ////////////////////////////////////
468:
469: SuccessfulExit:
470:
471: *returnNodeNum = nodeNum;
472: *returnIndex = index;
473: *foundRecord = foundIt;
474:
475: return noErr;
476:
477:
478: ////////////////////////////// Error Exit ///////////////////////////////////
479:
480: ErrorExit:
481:
482: (void) ReleaseNode (btreePtr, left);
483: (void) ReleaseNode (btreePtr, middle);
484: (void) ReleaseNode (btreePtr, right);
485:
486: *returnNodeNum = 0;
487: *returnIndex = 0;
488: *foundRecord = false;
489:
490: return err;
491: }
492:
493:
494:
495: /////////////////////////////// CheckInsertParams ///////////////////////////////
496:
497: OSStatus CheckInsertParams (FCB *filePtr,
498: BTreeIterator *iterator,
499: FSBufferDescriptor *record,
500: UInt16 recordLen )
501: {
502: BTreeControlBlockPtr btreePtr;
503:
504: if (filePtr == nil) return paramErr;
505:
506: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
507: if (btreePtr == nil) return fsBTInvalidFileErr;
508: if (iterator == nil) return paramErr;
509: if (record == nil) return paramErr;
510:
511: #if SupportsKeyDescriptors
512: if (btreePtr->keyDescPtr != nil)
513: {
514: OSStatus err;
515:
516: err = CheckKey (&iterator->key, btreePtr->keyDescPtr, btreePtr->maxKeyLength);
517: if (err != noErr)
518: return err;
519: }
520: #endif
521:
522: // check total key/record size limit
523: if ( CalcKeyRecordSize (CalcKeySize(btreePtr, &iterator->key), recordLen) > (btreePtr->nodeSize >> 1))
524: return fsBTRecordTooLargeErr;
525:
526: return noErr;
527: }
528:
529:
530:
531: /*-------------------------------------------------------------------------------
532: Routine: TrySimpleReplace - Attempts a simple insert, set, or replace.
533:
534: Function: If a hint exitst for the iterator, attempt to find the key in the hint
535: node. If the key is found, an insert operation fails. If the is not
536: found, a replace operation fails. If the key was not found, and the
537: insert position is greater than 0 and less than numRecords, the record
538: is inserted, provided there is enough freeSpace. If the key was found,
539: and there is more freeSpace than the difference between the new record
540: and the old record, the old record is deleted and the new record is
541: inserted.
542:
543: Assumptions: iterator key has already been checked by CheckKey
544:
545:
546: Input: btreePtr - description
547: iterator - description
548: record - description
549: recordLen - description
550: operation - description
551:
552:
553: Output: recordInserted - description
554:
555:
556: Result: noErr - success
557: E_RecordExits - insert operation failure
558: != noErr - GetNode, ReleaseNode, UpdateNode returned an error
559: -------------------------------------------------------------------------------*/
560:
561: OSStatus TrySimpleReplace (BTreeControlBlockPtr btreePtr,
562: NodeDescPtr nodePtr,
563: BTreeIterator *iterator,
564: FSBufferDescriptor *record,
565: UInt16 recordLen,
566: Boolean *recordInserted )
567: {
568: UInt32 oldSpace;
569: UInt32 spaceNeeded;
570: UInt16 index;
571: UInt16 keySize;
572: Boolean foundIt;
573: Boolean didItFit;
574:
575:
576: *recordInserted = false; // we'll assume this won't work...
577:
578: if ( nodePtr->type != kLeafNode )
579: return noErr; // we're in the weeds!
580:
581: foundIt = SearchNode (btreePtr, nodePtr, &iterator->key, &index);
582:
583: if ( foundIt == false )
584: return noErr; // we might be lost...
585:
586: keySize = CalcKeySize(btreePtr, &iterator->key); // includes length field
587:
588: spaceNeeded = CalcKeyRecordSize (keySize, recordLen);
589:
590: oldSpace = GetRecordSize (btreePtr, nodePtr, index);
591:
592: if ( spaceNeeded == oldSpace )
593: {
594: UInt8 * dst;
595:
596: dst = GetRecordAddress (btreePtr, nodePtr, index);
597:
598: if ( M_IsOdd (keySize) )
599: ++keySize; // add pad byte
600:
601: dst += keySize; // skip over key to point at record
602:
603: BlockMoveData(record->bufferAddress, dst, recordLen); // blast away...
604:
605: *recordInserted = true;
606: }
607: else if ( (GetNodeFreeSize(btreePtr, nodePtr) + oldSpace) >= spaceNeeded)
608: {
609: DeleteRecord (btreePtr, nodePtr, index);
610:
611: didItFit = InsertKeyRecord (btreePtr, nodePtr, index,
612: &iterator->key, KeyLength(btreePtr, &iterator->key),
613: record->bufferAddress, recordLen);
614: PanicIf (didItFit == false, "\pTrySimpleInsert: InsertKeyRecord returned false!");
615:
616: *recordInserted = true;
617: }
618: // else not enough space...
619:
620: return noErr;
621: }
622:
623:
624: /*-------------------------------------------------------------------------------
625: Routine: IsItAHint - checks the hint within a BTreeInterator.
626:
627: Function: checks the hint within a BTreeInterator. If it is non-zero, it may
628: possibly be valid.
629:
630: Input: btreePtr - pointer to control block for BTree file
631: iterator - pointer to BTreeIterator
632:
633: Output: answer - true if the hint looks reasonable
634: - false if the hint is 0
635:
636: Result: noErr - success
637: -------------------------------------------------------------------------------*/
638:
639:
640: OSStatus IsItAHint (BTreeControlBlockPtr btreePtr, BTreeIterator *iterator, Boolean *answer)
641: {
642: ++btreePtr->numHintChecks;
643:
644: //�� shouldn't we do a range check?
645: if (iterator->hint.nodeNum == 0)
646: {
647: *answer = false;
648: }
649: else
650: {
651: *answer = true;
652: ++btreePtr->numPossibleHints;
653: }
654:
655: return noErr;
656: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.