2 * Copyright (c) 2000, 2002, 2005-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 Contains: Single-node operations for the BTree Module.
33 Version: xxx put the technology version here xxx
35 Written by: Gordon Sheridan and Bill Bruffey
37 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
43 Other Contact: Mark Day
45 Technology: File Systems
52 Change History (most recent first):
54 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
55 <MOSXS> 4/113/99 djb Fix key size checking bug in CheckNode.
56 <MOSXS> 3/19/99 djb Added key size checking to CheckNode.
57 <MOSXS> 3/26/98 djb Added PrintNode for debugging.
58 <CS5> 9/4/97 djb Removed GetRightSiblingNode and GetLeftSiblingNode - they are
59 now macros. SearchNode is now in BTreeSearchNode.a.
60 <CS4> 8/22/97 djb Turn off debugging code in CheckKey.
61 <CS3> 7/24/97 djb Add summary traces for Get/Rel Node. Made GetRecordOffset into a
62 macro. Only call CheckNode if the node came from disk.
63 <CS2> 7/21/97 msd Make GetRecordByIndex check its record index input; it now
65 <CS1> 4/23/97 djb first checked in
67 <HFS3> 2/19/97 djb Changes to support big node cache.
68 <HFS2> 1/3/97 djb Added support for large keys.
69 <HFS1> 12/19/96 djb first checked in
72 History applicable to original Scarecrow Design:
74 <6> 10/25/96 ser Changing for new VFPI
75 <5> 9/17/96 dkh Add bounds checking to GetNode. Update GetNode to not assert
76 that CheckNode failed if the node is all zeroes. This can happen
77 if the hint case if the fetched node has been deallocated
78 <4> 3/7/96 dkh Change GetNewNode() to not use kGetEmptyBlock. Instead use
79 kGetBlock to fetch a block from the disk itself. \80\80\80 Why?
80 <3> 1/22/96 dkh Add #include Memory.h
81 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
82 <1> 10/18/95 rst Moved from Scarecrow project.
84 <17> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
85 <16> 1/31/95 prp GetBlockProc interface uses a 64 bit node number.
86 <15> 1/12/95 wjk Adopt Model FileSystem changes in D5.
87 <14> 9/30/94 prp Get in sync with D2 interface changes.
88 <13> 7/25/94 wjk Eliminate usage of BytePtr in favor of UInt8 *.
89 <12> 7/22/94 wjk Convert to the new set of header files.
90 <11> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
92 <10> 11/30/93 wjk Change some Ptr's to BytePtr's in function definitions so they
93 agree with their prototypes.
94 <9> 8/31/93 prp Use U64SetU instead of S64Set.
95 <8> 5/21/93 gs Maintain statistical counters on Get/Release node routines.
96 <7> 5/10/93 gs Change keySize parameter to keyLength for InsertKeyRecord
97 routine. Calculate number of bytes in key from keyLength to
98 account for length and pad bytes. Add GetChildNodeNum routine.
99 <6> 3/23/93 gs Add InsertKeyRecord routine.
100 <5> 2/8/93 gs Fix bug in SearchNode that caused "off by 1" error when final
101 compare was searchKey > trialKey. Add UpdateNode.
102 <4> 12/10/92 gs Change keyLength field of key to 'length'.
103 <3> 12/8/92 gs Incorporate suggestions from preliminary code review.
104 <2> 12/2/92 gs Implement routines.
105 <1> 11/15/92 gs Define routine interfaces.
109 #include "../headers/BTreesPrivate.h"
113 ///////////////////////// BTree Module Node Operations //////////////////////////
115 // GetNode - Call FS Agent to get node
116 // GetNewNode - Call FS Agent to get a new node
117 // ReleaseNode - Call FS Agent to release node obtained by GetNode.
118 // UpdateNode - Mark a node as dirty and call FS Agent to release it.
120 // ClearNode - Clear a node to all zeroes.
122 // InsertRecord - Inserts a record into a BTree node.
123 // InsertKeyRecord - Inserts a key and record pair into a BTree node.
124 // DeleteRecord - Deletes a record from a BTree node.
126 // SearchNode - Return index for record that matches key.
127 // LocateRecord - Return pointer to key and data, and size of data.
129 // GetNodeDataSize - Return the amount of space used for data in the node.
130 // GetNodeFreeSize - Return the amount of free space in the node.
132 // GetRecordOffset - Return the offset for record "index".
133 // GetRecordAddress - Return address of record "index".
134 // GetOffsetAddress - Return address of offset for record "index".
136 // InsertOffset - Inserts a new offset into a node.
137 // DeleteOffset - Deletes an offset from a node.
139 /////////////////////////////////////////////////////////////////////////////////
143 ////////////////////// Routines Internal To BTreeNodeOps.c //////////////////////
145 u_int16_t
GetRecordOffset (BTreeControlBlockPtr btree
,
149 u_int16_t
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
153 void InsertOffset (BTreeControlBlockPtr btreePtr
,
158 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
163 /////////////////////////////////////////////////////////////////////////////////
165 #define GetRecordOffset(btreePtr,node,index) (*(short *) ((u_int8_t *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
168 #include <sys/systm.h>
169 #define PRINTIT kprintf
170 static void PrintNode(const NodeDescPtr node
, u_int16_t nodeSize
, u_int32_t nodeNumber
);
171 #endif /* HFS_DIAGNOSTIC */
176 /*-------------------------------------------------------------------------------
178 Routine: GetNode - Call FS Agent to get node
180 Function: Gets an existing BTree node from FS Agent and verifies it.
182 Input: btreePtr - pointer to BTree control block
183 nodeNum - number of node to request
185 Output: nodePtr - pointer to beginning of node (nil if error)
190 -------------------------------------------------------------------------------*/
192 OSStatus
GetNode (BTreeControlBlockPtr btreePtr
,
198 GetBlockProcPtr getNodeProc
;
202 // is nodeNum within proper range?
203 if( nodeNum
>= btreePtr
->totalNodes
)
205 Panic("GetNode:nodeNum >= totalNodes");
206 err
= fsBTInvalidNodeErr
;
210 nodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
213 if ( flags
& kGetNodeHint
)
215 options
|= kGetBlockHint
;
218 getNodeProc
= btreePtr
->getBlockProc
;
219 err
= getNodeProc (btreePtr
->fileRefNum
,
226 Panic ("GetNode: getNodeProc returned error.");
229 ++btreePtr
->numGetNodes
;
234 nodePtr
->buffer
= nil
;
235 nodePtr
->blockHeader
= nil
;
242 /*-------------------------------------------------------------------------------
244 Routine: GetNewNode - Call FS Agent to get a new node
246 Function: Gets a new BTree node from FS Agent and initializes it to an empty
249 Input: btreePtr - pointer to BTree control block
250 nodeNum - number of node to request
252 Output: returnNodePtr - pointer to beginning of node (nil if error)
254 Result: noErr - success
256 -------------------------------------------------------------------------------*/
258 OSStatus
GetNewNode (BTreeControlBlockPtr btreePtr
,
260 NodeRec
*returnNodePtr
)
265 GetBlockProcPtr getNodeProc
;
268 //////////////////////// get buffer for new node ////////////////////////////
270 returnNodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
272 getNodeProc
= btreePtr
->getBlockProc
;
273 err
= getNodeProc (btreePtr
->fileRefNum
,
275 kGetBlock
+kGetEmptyBlock
,
280 Panic ("GetNewNode: getNodeProc returned error.");
281 // returnNodePtr->buffer = nil;
284 ++btreePtr
->numGetNewNodes
;
287 ////////////////////////// initialize the node //////////////////////////////
289 node
= returnNodePtr
->buffer
;
291 ClearNode (btreePtr
, node
); // clear the node
293 pos
= (char *)node
+ btreePtr
->nodeSize
- 2; // find address of last offset
294 *(u_int16_t
*)pos
= sizeof (BTNodeDescriptor
); // set offset to beginning of free space
302 /*-------------------------------------------------------------------------------
304 Routine: ReleaseNode - Call FS Agent to release node obtained by GetNode.
306 Function: Informs the FS Agent that a BTree node may be released.
308 Input: btreePtr - pointer to BTree control block
309 nodeNum - number of node to release
311 Result: noErr - success
313 -------------------------------------------------------------------------------*/
315 OSStatus
ReleaseNode (BTreeControlBlockPtr btreePtr
,
319 ReleaseBlockProcPtr releaseNodeProc
;
324 if (nodePtr
->buffer
!= nil
)
326 releaseNodeProc
= btreePtr
->releaseBlockProc
;
327 err
= releaseNodeProc (btreePtr
->fileRefNum
,
330 PanicIf (err
, "ReleaseNode: releaseNodeProc returned error.");
331 ++btreePtr
->numReleaseNodes
;
334 nodePtr
->buffer
= nil
;
335 nodePtr
->blockHeader
= nil
;
343 /*-------------------------------------------------------------------------------
345 Routine: TrashNode - Call FS Agent to release node obtained by GetNode, and
346 not store it...mark it as bad.
348 Function: Informs the FS Agent that a BTree node may be released and thrown away.
350 Input: btreePtr - pointer to BTree control block
351 nodeNum - number of node to release
353 Result: noErr - success
355 -------------------------------------------------------------------------------*/
357 OSStatus
TrashNode (BTreeControlBlockPtr btreePtr
,
361 ReleaseBlockProcPtr releaseNodeProc
;
366 if (nodePtr
->buffer
!= nil
)
368 releaseNodeProc
= btreePtr
->releaseBlockProc
;
369 err
= releaseNodeProc (btreePtr
->fileRefNum
,
371 kReleaseBlock
| kTrashBlock
);
372 PanicIf (err
, "TrashNode: releaseNodeProc returned error.");
373 ++btreePtr
->numReleaseNodes
;
376 nodePtr
->buffer
= nil
;
377 nodePtr
->blockHeader
= nil
;
384 /*-------------------------------------------------------------------------------
386 Routine: UpdateNode - Mark a node as dirty and call FS Agent to release it.
388 Function: Marks a BTree node dirty and informs the FS Agent that it may be released.
390 Input: btreePtr - pointer to BTree control block
391 nodeNum - number of node to release
392 transactionID - ID of transaction this node update is a part of
393 flags - special flags to pass to ReleaseNodeProc
395 Result: noErr - success
397 -------------------------------------------------------------------------------*/
399 OSStatus
UpdateNode (BTreeControlBlockPtr btreePtr
,
401 u_int32_t transactionID
,
404 #pragma unused(transactionID)
407 ReleaseBlockProcPtr releaseNodeProc
;
412 if (nodePtr
->buffer
!= nil
) // Why call UpdateNode if nil ?!?
414 releaseNodeProc
= btreePtr
->releaseBlockProc
;
415 err
= releaseNodeProc (btreePtr
->fileRefNum
,
417 flags
| kMarkBlockDirty
);
418 ++btreePtr
->numUpdateNodes
;
422 nodePtr
->buffer
= nil
;
423 nodePtr
->blockHeader
= nil
;
435 static void PrintNode(const NodeDescPtr node
, u_int16_t nodeSize
, u_int32_t nodeNumber
)
444 PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber
, nodeNumber
);
447 lp
= (u_int32_t
*) node
;
451 PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int
)offset
++, *lp
++, *lp
++, *lp
++, *lp
++);
456 /*-------------------------------------------------------------------------------
458 Routine: ClearNode - Clear a node to all zeroes.
460 Function: Writes zeroes from beginning of node for nodeSize bytes.
462 Input: btreePtr - pointer to BTree control block
463 node - pointer to node to clear
466 -------------------------------------------------------------------------------*/
468 void ClearNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
470 ClearMemory( node
, btreePtr
->nodeSize
);
473 /*-------------------------------------------------------------------------------
475 Routine: InsertRecord - Inserts a record into a BTree node.
479 Note: Record size must be even!
481 Input: btreePtr - pointer to BTree control block
482 node - pointer to node to insert the record
483 index - position record is to be inserted
484 recPtr - pointer to record to insert
486 Result: noErr - success
487 fsBTFullErr - record larger than remaining free space.
488 -------------------------------------------------------------------------------*/
490 Boolean
InsertRecord (BTreeControlBlockPtr btreePtr
,
497 u_int16_t indexOffset
;
498 u_int16_t freeOffset
;
499 u_int16_t bytesToMove
;
503 //// will new record fit in node?
505 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
506 //\80\80 we could get freeOffset & calc freeSpace
507 if ( freeSpace
< recSize
+ 2)
513 //// make hole for new record
515 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
516 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
518 src
= ((Ptr
) node
) + indexOffset
;
519 dst
= ((Ptr
) src
) + recSize
;
520 bytesToMove
= freeOffset
- indexOffset
;
522 MoveRecordsRight (src
, dst
, bytesToMove
);
525 //// adjust offsets for moved records
527 InsertOffset (btreePtr
, node
, index
, recSize
);
530 //// move in the new record
532 dst
= ((Ptr
) node
) + indexOffset
;
533 MoveRecordsLeft (recPtr
, dst
, recSize
);
540 /*-------------------------------------------------------------------------------
542 Routine: InsertKeyRecord - Inserts a record into a BTree node.
546 Note: Record size must be even!
548 Input: btreePtr - pointer to BTree control block
549 node - pointer to node to insert the record
550 index - position record is to be inserted
551 keyPtr - pointer to key for record to insert
552 keyLength - length of key (or maxKeyLength)
553 recPtr - pointer to record to insert
554 recSize - number of bytes to copy for record
556 Result: noErr - success
557 fsBTFullErr - record larger than remaining free space.
558 -------------------------------------------------------------------------------*/
560 Boolean
InsertKeyRecord (BTreeControlBlockPtr btreePtr
,
569 u_int16_t indexOffset
;
570 u_int16_t freeOffset
;
571 u_int16_t bytesToMove
;
575 u_int16_t rawKeyLength
;
576 u_int16_t sizeOfLength
;
578 //// calculate actual key size
580 if ( btreePtr
->attributes
& kBTBigKeysMask
)
581 keySize
= keyLength
+ sizeof(u_int16_t
);
583 keySize
= keyLength
+ sizeof(u_int8_t
);
585 if ( M_IsOdd (keySize
) )
586 ++keySize
; // add pad byte
589 //// will new record fit in node?
591 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
592 //\80\80 we could get freeOffset & calc freeSpace
593 if ( freeSpace
< keySize
+ recSize
+ 2)
599 //// make hole for new record
601 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
602 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
604 src
= ((u_int8_t
*) node
) + indexOffset
;
605 dst
= ((u_int8_t
*) src
) + keySize
+ recSize
;
606 bytesToMove
= freeOffset
- indexOffset
;
608 MoveRecordsRight (src
, dst
, bytesToMove
);
611 //// adjust offsets for moved records
613 InsertOffset (btreePtr
, node
, index
, keySize
+ recSize
);
618 dst
= ((u_int8_t
*) node
) + indexOffset
;
620 if ( btreePtr
->attributes
& kBTBigKeysMask
)
622 *((u_int16_t
*)dst
) = keyLength
; // use keyLength rather than key.length
623 dst
= (u_int8_t
*) (((u_int16_t
*)dst
) + 1);
624 rawKeyLength
= keyPtr
->length16
;
629 *dst
++ = keyLength
; // use keyLength rather than key.length
630 rawKeyLength
= keyPtr
->length8
;
634 MoveRecordsLeft ( ((u_int8_t
*) keyPtr
) + sizeOfLength
, dst
, rawKeyLength
); // copy key
637 bytesToMove
= keySize
- rawKeyLength
;
639 ClearMemory (dst
+ rawKeyLength
, bytesToMove
); // clear pad bytes in index key
642 //// copy record data
644 dst
= ((u_int8_t
*) node
) + indexOffset
+ keySize
;
645 MoveRecordsLeft (recPtr
, dst
, recSize
);
652 /*-------------------------------------------------------------------------------
654 Routine: DeleteRecord - Deletes a record from a BTree node.
658 Input: btreePtr - pointer to BTree control block
659 node - pointer to node to insert the record
660 index - position record is to be inserted
663 -------------------------------------------------------------------------------*/
665 void DeleteRecord (BTreeControlBlockPtr btreePtr
,
676 //// compress records
677 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
678 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
679 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
681 src
= ((Ptr
) node
) + nextOffset
;
682 dst
= ((Ptr
) node
) + indexOffset
;
683 bytesToMove
= freeOffset
- nextOffset
;
685 MoveRecordsLeft (src
, dst
, bytesToMove
);
687 //// Adjust the offsets
688 DeleteOffset (btreePtr
, node
, index
);
690 /* clear out new free space */
691 bytesToMove
= nextOffset
- indexOffset
;
692 ClearMemory(GetRecordAddress(btreePtr
, node
, node
->numRecords
), bytesToMove
);
698 /*-------------------------------------------------------------------------------
700 Routine: SearchNode - Return index for record that matches key.
702 Function: Returns the record index for the record that matches the search key.
703 If no record was found that matches the search key, the "insert index"
704 of where the record should go is returned instead.
706 Algorithm: A binary search algorithm is used to find the specified key.
708 Input: btreePtr - pointer to BTree control block
709 node - pointer to node that contains the record
710 searchKey - pointer to the key to match
712 Output: index - pointer to beginning of key for record
714 Result: true - success (index = record index)
715 false - key did not match anything in node (index = insert index)
716 -------------------------------------------------------------------------------*/
718 SearchNode( BTreeControlBlockPtr btreePtr
,
721 u_int16_t
*returnIndex
)
729 KeyCompareProcPtr compareProc
= btreePtr
->keyCompareProc
;
732 upperBound
= node
->numRecords
- 1;
733 offset
= (u_int16_t
*) ((u_int8_t
*)(node
) + (btreePtr
)->nodeSize
- kOffsetSize
);
735 while (lowerBound
<= upperBound
) {
736 index
= (lowerBound
+ upperBound
) >> 1;
738 trialKey
= (KeyPtr
) ((u_int8_t
*)node
+ *(offset
- index
));
740 result
= compareProc(searchKey
, trialKey
);
743 upperBound
= index
- 1; /* search < trial */
744 } else if (result
> 0) {
745 lowerBound
= index
+ 1; /* search > trial */
747 *returnIndex
= index
; /* search == trial */
752 *returnIndex
= lowerBound
; /* lowerBound is insert index */
757 /*-------------------------------------------------------------------------------
759 Routine: GetRecordByIndex - Return pointer to key and data, and size of data.
761 Function: Returns a pointer to beginning of key for record, a pointer to the
762 beginning of the data for the record, and the size of the record data
763 (does not include the size of the key).
765 Input: btreePtr - pointer to BTree control block
766 node - pointer to node that contains the record
767 index - index of record to get
769 Output: keyPtr - pointer to beginning of key for record
770 dataPtr - pointer to beginning of data for record
771 dataSize - size of the data portion of the record
774 -------------------------------------------------------------------------------*/
776 OSStatus
GetRecordByIndex (BTreeControlBlockPtr btreePtr
,
781 u_int16_t
*dataSize
)
784 u_int16_t nextOffset
;
788 // Make sure index is valid (in range 0..numRecords-1)
790 if (index
>= node
->numRecords
)
791 return fsBTRecordNotFoundErr
;
794 offset
= GetRecordOffset (btreePtr
, node
, index
);
795 *keyPtr
= (KeyPtr
) ((Ptr
)node
+ offset
);
798 keySize
= CalcKeySize(btreePtr
, *keyPtr
);
799 if ( M_IsOdd (keySize
) )
800 ++keySize
; // add pad byte
802 offset
+= keySize
; // add the key length to find data offset
803 *dataPtr
= (u_int8_t
*) node
+ offset
;
806 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
807 *dataSize
= nextOffset
- offset
;
814 /*-------------------------------------------------------------------------------
816 Routine: GetNodeDataSize - Return the amount of space used for data in the node.
818 Function: Gets the size of the data currently contained in a node, excluding
819 the node header. (record data + offset overhead)
821 Input: btreePtr - pointer to BTree control block
822 node - pointer to node that contains the record
824 Result: - number of bytes used for data and offsets in the node.
825 -------------------------------------------------------------------------------*/
827 u_int16_t
GetNodeDataSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
829 u_int16_t freeOffset
;
831 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
833 return freeOffset
+ (node
->numRecords
<< 1) - sizeof (BTNodeDescriptor
);
838 /*-------------------------------------------------------------------------------
840 Routine: GetNodeFreeSize - Return the amount of free space in the node.
844 Input: btreePtr - pointer to BTree control block
845 node - pointer to node that contains the record
847 Result: - number of bytes of free space in the node.
848 -------------------------------------------------------------------------------*/
850 u_int16_t
GetNodeFreeSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
852 u_int16_t freeOffset
;
854 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
); //\80\80 inline?
856 return btreePtr
->nodeSize
- freeOffset
- (node
->numRecords
<< 1) - kOffsetSize
;
861 /*-------------------------------------------------------------------------------
863 Routine: GetRecordOffset - Return the offset for record "index".
867 Input: btreePtr - pointer to BTree control block
868 node - pointer to node that contains the record
869 index - record to obtain offset for
871 Result: - offset (in bytes) from beginning of node of record specified by index
872 -------------------------------------------------------------------------------*/
873 // make this a macro (for inlining)
875 u_int16_t
GetRecordOffset (BTreeControlBlockPtr btreePtr
,
882 pos
= (u_int8_t
*)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
;
884 return *(short *)pos
;
890 /*-------------------------------------------------------------------------------
892 Routine: GetRecordAddress - Return address of record "index".
896 Input: btreePtr - pointer to BTree control block
897 node - pointer to node that contains the record
898 index - record to obtain offset address for
900 Result: - pointer to record "index".
901 -------------------------------------------------------------------------------*/
902 // make this a macro (for inlining)
904 u_int8_t
* GetRecordAddress (BTreeControlBlockPtr btreePtr
,
910 pos
= (u_int8_t
*)node
+ GetRecordOffset (btreePtr
, node
, index
);
918 /*-------------------------------------------------------------------------------
920 Routine: GetRecordSize - Return size of record "index".
924 Note: This does not work on the FreeSpace index!
926 Input: btreePtr - pointer to BTree control block
927 node - pointer to node that contains the record
928 index - record to obtain record size for
930 Result: - size of record "index".
931 -------------------------------------------------------------------------------*/
933 u_int16_t
GetRecordSize (BTreeControlBlockPtr btreePtr
,
939 pos
= (u_int16_t
*) ((Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
);
941 return *(pos
-1) - *pos
;
946 /*-------------------------------------------------------------------------------
947 Routine: GetOffsetAddress - Return address of offset for record "index".
951 Input: btreePtr - pointer to BTree control block
952 node - pointer to node that contains the record
953 index - record to obtain offset address for
955 Result: - pointer to offset for record "index".
956 -------------------------------------------------------------------------------*/
958 u_int16_t
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
964 pos
= (Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) -2;
966 return (u_int16_t
*)pos
;
971 /*-------------------------------------------------------------------------------
972 Routine: GetChildNodeNum - Return child node number from index record "index".
974 Function: Returns the first u_int32_t stored after the key for record "index".
976 Assumes: The node is an Index Node.
977 The key.length stored at record "index" is ODD. //\80\80 change for variable length index keys
979 Input: btreePtr - pointer to BTree control block
980 node - pointer to node that contains the record
981 index - record to obtain child node number from
983 Result: - child node number from record "index".
984 -------------------------------------------------------------------------------*/
986 u_int32_t
GetChildNodeNum (BTreeControlBlockPtr btreePtr
,
992 pos
= GetRecordAddress (btreePtr
, nodePtr
, index
);
993 pos
+= CalcKeySize(btreePtr
, (BTreeKey
*) pos
); // key.length + size of length field
995 return *(u_int32_t
*)pos
;
1000 /*-------------------------------------------------------------------------------
1001 Routine: InsertOffset - Add an offset and adjust existing offsets by delta.
1003 Function: Add an offset at 'index' by shifting 'index+1' through the last offset
1004 and adjusting them by 'delta', the size of the record to be inserted.
1005 The number of records contained in the node is also incremented.
1007 Input: btreePtr - pointer to BTree control block
1008 node - pointer to node
1009 index - index at which to insert record
1010 delta - size of record to be inserted
1013 -------------------------------------------------------------------------------*/
1015 void InsertOffset (BTreeControlBlockPtr btreePtr
,
1020 u_int16_t
*src
, *dst
;
1021 u_int16_t numOffsets
;
1023 src
= GetOffsetAddress (btreePtr
, node
, node
->numRecords
); // point to free offset
1024 dst
= src
- 1; // point to new offset
1025 numOffsets
= node
->numRecords
++ - index
; // subtract index & postincrement
1028 *dst
++ = *src
++ + delta
; // to tricky?
1029 } while (numOffsets
--);
1034 /*-------------------------------------------------------------------------------
1036 Routine: DeleteOffset - Delete an offset.
1038 Function: Delete the offset at 'index' by shifting 'index+1' through the last offset
1039 and adjusting them by the size of the record 'index'.
1040 The number of records contained in the node is also decremented.
1042 Input: btreePtr - pointer to BTree control block
1043 node - pointer to node
1044 index - index at which to delete record
1047 -------------------------------------------------------------------------------*/
1049 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
1053 u_int16_t
*src
, *dst
;
1054 u_int16_t numOffsets
;
1057 dst
= GetOffsetAddress (btreePtr
, node
, index
);
1059 delta
= *src
- *dst
;
1060 numOffsets
= --node
->numRecords
- index
; // predecrement numRecords & subtract index
1062 while (numOffsets
--)
1064 *--dst
= *--src
- delta
; // work our way left