2 * Copyright (c) 2000, 2002, 2005 Apple Computer, 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
,
197 GetBlockProcPtr getNodeProc
;
200 //\80\80 is nodeNum within proper range?
201 if( nodeNum
>= btreePtr
->totalNodes
)
203 Panic("\pGetNode:nodeNum >= totalNodes");
204 err
= fsBTInvalidNodeErr
;
208 nodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
210 getNodeProc
= btreePtr
->getBlockProc
;
211 err
= getNodeProc (btreePtr
->fileRefNum
,
218 Panic ("\pGetNode: getNodeProc returned error.");
219 // nodePtr->buffer = nil;
222 ++btreePtr
->numGetNodes
;
227 nodePtr
->buffer
= nil
;
228 nodePtr
->blockHeader
= nil
;
235 /*-------------------------------------------------------------------------------
237 Routine: GetNewNode - Call FS Agent to get a new node
239 Function: Gets a new BTree node from FS Agent and initializes it to an empty
242 Input: btreePtr - pointer to BTree control block
243 nodeNum - number of node to request
245 Output: returnNodePtr - pointer to beginning of node (nil if error)
247 Result: noErr - success
249 -------------------------------------------------------------------------------*/
251 OSStatus
GetNewNode (BTreeControlBlockPtr btreePtr
,
253 NodeRec
*returnNodePtr
)
258 GetBlockProcPtr getNodeProc
;
261 //////////////////////// get buffer for new node ////////////////////////////
263 returnNodePtr
->blockSize
= btreePtr
->nodeSize
; // indicate the size of a node
265 getNodeProc
= btreePtr
->getBlockProc
;
266 err
= getNodeProc (btreePtr
->fileRefNum
,
268 kGetBlock
+kGetEmptyBlock
,
273 Panic ("\pGetNewNode: getNodeProc returned error.");
274 // returnNodePtr->buffer = nil;
277 ++btreePtr
->numGetNewNodes
;
280 ////////////////////////// initialize the node //////////////////////////////
282 node
= returnNodePtr
->buffer
;
284 ClearNode (btreePtr
, node
); // clear the node
286 pos
= (char *)node
+ btreePtr
->nodeSize
- 2; // find address of last offset
287 *(u_int16_t
*)pos
= sizeof (BTNodeDescriptor
); // set offset to beginning of free space
295 /*-------------------------------------------------------------------------------
297 Routine: ReleaseNode - Call FS Agent to release node obtained by GetNode.
299 Function: Informs the FS Agent that a BTree node may be released.
301 Input: btreePtr - pointer to BTree control block
302 nodeNum - number of node to release
304 Result: noErr - success
306 -------------------------------------------------------------------------------*/
308 OSStatus
ReleaseNode (BTreeControlBlockPtr btreePtr
,
312 ReleaseBlockProcPtr releaseNodeProc
;
317 if (nodePtr
->buffer
!= nil
)
319 releaseNodeProc
= btreePtr
->releaseBlockProc
;
320 err
= releaseNodeProc (btreePtr
->fileRefNum
,
323 PanicIf (err
, "\pReleaseNode: releaseNodeProc returned error.");
324 ++btreePtr
->numReleaseNodes
;
327 nodePtr
->buffer
= nil
;
328 nodePtr
->blockHeader
= nil
;
336 /*-------------------------------------------------------------------------------
338 Routine: TrashNode - Call FS Agent to release node obtained by GetNode, and
339 not store it...mark it as bad.
341 Function: Informs the FS Agent that a BTree node may be released and thrown away.
343 Input: btreePtr - pointer to BTree control block
344 nodeNum - number of node to release
346 Result: noErr - success
348 -------------------------------------------------------------------------------*/
350 OSStatus
TrashNode (BTreeControlBlockPtr btreePtr
,
354 ReleaseBlockProcPtr releaseNodeProc
;
359 if (nodePtr
->buffer
!= nil
)
361 releaseNodeProc
= btreePtr
->releaseBlockProc
;
362 err
= releaseNodeProc (btreePtr
->fileRefNum
,
364 kReleaseBlock
| kTrashBlock
);
365 PanicIf (err
, "\TrashNode: releaseNodeProc returned error.");
366 ++btreePtr
->numReleaseNodes
;
369 nodePtr
->buffer
= nil
;
370 nodePtr
->blockHeader
= nil
;
377 /*-------------------------------------------------------------------------------
379 Routine: UpdateNode - Mark a node as dirty and call FS Agent to release it.
381 Function: Marks a BTree node dirty and informs the FS Agent that it may be released.
383 Input: btreePtr - pointer to BTree control block
384 nodeNum - number of node to release
385 transactionID - ID of transaction this node update is a part of
386 flags - special flags to pass to ReleaseNodeProc
388 Result: noErr - success
390 -------------------------------------------------------------------------------*/
392 OSStatus
UpdateNode (BTreeControlBlockPtr btreePtr
,
394 u_int32_t transactionID
,
397 #pragma unused(transactionID)
400 ReleaseBlockProcPtr releaseNodeProc
;
405 if (nodePtr
->buffer
!= nil
) // Why call UpdateNode if nil ?!?
407 releaseNodeProc
= btreePtr
->releaseBlockProc
;
408 err
= releaseNodeProc (btreePtr
->fileRefNum
,
410 flags
| kMarkBlockDirty
);
411 ++btreePtr
->numUpdateNodes
;
415 nodePtr
->buffer
= nil
;
416 nodePtr
->blockHeader
= nil
;
428 static void PrintNode(const NodeDescPtr node
, u_int16_t nodeSize
, u_int32_t nodeNumber
)
437 PRINTIT("Dump of B-tree node #%ld ($%08lX)\n", nodeNumber
, nodeNumber
);
440 lp
= (u_int32_t
*) node
;
444 PRINTIT("%04X: %08lX %08lX %08lX %08lX\n", (u_int
)offset
++, *lp
++, *lp
++, *lp
++, *lp
++);
449 /*-------------------------------------------------------------------------------
451 Routine: ClearNode - Clear a node to all zeroes.
453 Function: Writes zeroes from beginning of node for nodeSize bytes.
455 Input: btreePtr - pointer to BTree control block
456 node - pointer to node to clear
459 -------------------------------------------------------------------------------*/
461 void ClearNode (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
463 ClearMemory( node
, btreePtr
->nodeSize
);
466 /*-------------------------------------------------------------------------------
468 Routine: InsertRecord - Inserts a record into a BTree node.
472 Note: Record size must be even!
474 Input: btreePtr - pointer to BTree control block
475 node - pointer to node to insert the record
476 index - position record is to be inserted
477 recPtr - pointer to record to insert
479 Result: noErr - success
480 fsBTFullErr - record larger than remaining free space.
481 -------------------------------------------------------------------------------*/
483 Boolean
InsertRecord (BTreeControlBlockPtr btreePtr
,
490 u_int16_t indexOffset
;
491 u_int16_t freeOffset
;
492 u_int16_t bytesToMove
;
496 //// will new record fit in node?
498 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
499 //\80\80 we could get freeOffset & calc freeSpace
500 if ( freeSpace
< recSize
+ 2)
506 //// make hole for new record
508 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
509 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
511 src
= ((Ptr
) node
) + indexOffset
;
512 dst
= ((Ptr
) src
) + recSize
;
513 bytesToMove
= freeOffset
- indexOffset
;
515 MoveRecordsRight (src
, dst
, bytesToMove
);
518 //// adjust offsets for moved records
520 InsertOffset (btreePtr
, node
, index
, recSize
);
523 //// move in the new record
525 dst
= ((Ptr
) node
) + indexOffset
;
526 MoveRecordsLeft (recPtr
, dst
, recSize
);
533 /*-------------------------------------------------------------------------------
535 Routine: InsertKeyRecord - Inserts a record into a BTree node.
539 Note: Record size must be even!
541 Input: btreePtr - pointer to BTree control block
542 node - pointer to node to insert the record
543 index - position record is to be inserted
544 keyPtr - pointer to key for record to insert
545 keyLength - length of key (or maxKeyLength)
546 recPtr - pointer to record to insert
547 recSize - number of bytes to copy for record
549 Result: noErr - success
550 fsBTFullErr - record larger than remaining free space.
551 -------------------------------------------------------------------------------*/
553 Boolean
InsertKeyRecord (BTreeControlBlockPtr btreePtr
,
562 u_int16_t indexOffset
;
563 u_int16_t freeOffset
;
564 u_int16_t bytesToMove
;
568 u_int16_t rawKeyLength
;
569 u_int16_t sizeOfLength
;
571 //// calculate actual key size
573 if ( btreePtr
->attributes
& kBTBigKeysMask
)
574 keySize
= keyLength
+ sizeof(u_int16_t
);
576 keySize
= keyLength
+ sizeof(u_int8_t
);
578 if ( M_IsOdd (keySize
) )
579 ++keySize
; // add pad byte
582 //// will new record fit in node?
584 freeSpace
= GetNodeFreeSize (btreePtr
, node
);
585 //\80\80 we could get freeOffset & calc freeSpace
586 if ( freeSpace
< keySize
+ recSize
+ 2)
592 //// make hole for new record
594 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
595 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
597 src
= ((u_int8_t
*) node
) + indexOffset
;
598 dst
= ((u_int8_t
*) src
) + keySize
+ recSize
;
599 bytesToMove
= freeOffset
- indexOffset
;
601 MoveRecordsRight (src
, dst
, bytesToMove
);
604 //// adjust offsets for moved records
606 InsertOffset (btreePtr
, node
, index
, keySize
+ recSize
);
611 dst
= ((u_int8_t
*) node
) + indexOffset
;
613 if ( btreePtr
->attributes
& kBTBigKeysMask
)
615 *((u_int16_t
*)dst
) = keyLength
; // use keyLength rather than key.length
616 dst
= (u_int8_t
*) (((u_int16_t
*)dst
) + 1);
617 rawKeyLength
= keyPtr
->length16
;
622 *dst
++ = keyLength
; // use keyLength rather than key.length
623 rawKeyLength
= keyPtr
->length8
;
627 MoveRecordsLeft ( ((u_int8_t
*) keyPtr
) + sizeOfLength
, dst
, rawKeyLength
); // copy key
630 bytesToMove
= keySize
- rawKeyLength
;
632 ClearMemory (dst
+ rawKeyLength
, bytesToMove
); // clear pad bytes in index key
635 //// copy record data
637 dst
= ((u_int8_t
*) node
) + indexOffset
+ keySize
;
638 MoveRecordsLeft (recPtr
, dst
, recSize
);
645 /*-------------------------------------------------------------------------------
647 Routine: DeleteRecord - Deletes a record from a BTree node.
651 Input: btreePtr - pointer to BTree control block
652 node - pointer to node to insert the record
653 index - position record is to be inserted
656 -------------------------------------------------------------------------------*/
658 void DeleteRecord (BTreeControlBlockPtr btreePtr
,
669 //// compress records
670 indexOffset
= GetRecordOffset (btreePtr
, node
, index
);
671 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
672 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
674 src
= ((Ptr
) node
) + nextOffset
;
675 dst
= ((Ptr
) node
) + indexOffset
;
676 bytesToMove
= freeOffset
- nextOffset
;
678 MoveRecordsLeft (src
, dst
, bytesToMove
);
680 //// Adjust the offsets
681 DeleteOffset (btreePtr
, node
, index
);
683 /* clear out new free space */
684 bytesToMove
= nextOffset
- indexOffset
;
685 ClearMemory(GetRecordAddress(btreePtr
, node
, node
->numRecords
), bytesToMove
);
691 /*-------------------------------------------------------------------------------
693 Routine: SearchNode - Return index for record that matches key.
695 Function: Returns the record index for the record that matches the search key.
696 If no record was found that matches the search key, the "insert index"
697 of where the record should go is returned instead.
699 Algorithm: A binary search algorithm is used to find the specified key.
701 Input: btreePtr - pointer to BTree control block
702 node - pointer to node that contains the record
703 searchKey - pointer to the key to match
705 Output: index - pointer to beginning of key for record
707 Result: true - success (index = record index)
708 false - key did not match anything in node (index = insert index)
709 -------------------------------------------------------------------------------*/
711 SearchNode( BTreeControlBlockPtr btreePtr
,
714 u_int16_t
*returnIndex
)
722 KeyCompareProcPtr compareProc
= btreePtr
->keyCompareProc
;
725 upperBound
= node
->numRecords
- 1;
726 offset
= (u_int16_t
*) ((u_int8_t
*)(node
) + (btreePtr
)->nodeSize
- kOffsetSize
);
728 while (lowerBound
<= upperBound
) {
729 index
= (lowerBound
+ upperBound
) >> 1;
731 trialKey
= (KeyPtr
) ((u_int8_t
*)node
+ *(offset
- index
));
733 result
= compareProc(searchKey
, trialKey
);
736 upperBound
= index
- 1; /* search < trial */
737 } else if (result
> 0) {
738 lowerBound
= index
+ 1; /* search > trial */
740 *returnIndex
= index
; /* search == trial */
745 *returnIndex
= lowerBound
; /* lowerBound is insert index */
750 /*-------------------------------------------------------------------------------
752 Routine: GetRecordByIndex - Return pointer to key and data, and size of data.
754 Function: Returns a pointer to beginning of key for record, a pointer to the
755 beginning of the data for the record, and the size of the record data
756 (does not include the size of the key).
758 Input: btreePtr - pointer to BTree control block
759 node - pointer to node that contains the record
760 index - index of record to get
762 Output: keyPtr - pointer to beginning of key for record
763 dataPtr - pointer to beginning of data for record
764 dataSize - size of the data portion of the record
767 -------------------------------------------------------------------------------*/
769 OSStatus
GetRecordByIndex (BTreeControlBlockPtr btreePtr
,
774 u_int16_t
*dataSize
)
777 u_int16_t nextOffset
;
781 // Make sure index is valid (in range 0..numRecords-1)
783 if (index
>= node
->numRecords
)
784 return fsBTRecordNotFoundErr
;
787 offset
= GetRecordOffset (btreePtr
, node
, index
);
788 *keyPtr
= (KeyPtr
) ((Ptr
)node
+ offset
);
791 keySize
= CalcKeySize(btreePtr
, *keyPtr
);
792 if ( M_IsOdd (keySize
) )
793 ++keySize
; // add pad byte
795 offset
+= keySize
; // add the key length to find data offset
796 *dataPtr
= (u_int8_t
*) node
+ offset
;
799 nextOffset
= GetRecordOffset (btreePtr
, node
, index
+ 1);
800 *dataSize
= nextOffset
- offset
;
807 /*-------------------------------------------------------------------------------
809 Routine: GetNodeDataSize - Return the amount of space used for data in the node.
811 Function: Gets the size of the data currently contained in a node, excluding
812 the node header. (record data + offset overhead)
814 Input: btreePtr - pointer to BTree control block
815 node - pointer to node that contains the record
817 Result: - number of bytes used for data and offsets in the node.
818 -------------------------------------------------------------------------------*/
820 u_int16_t
GetNodeDataSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
822 u_int16_t freeOffset
;
824 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
);
826 return freeOffset
+ (node
->numRecords
<< 1) - sizeof (BTNodeDescriptor
);
831 /*-------------------------------------------------------------------------------
833 Routine: GetNodeFreeSize - Return the amount of free space in the node.
837 Input: btreePtr - pointer to BTree control block
838 node - pointer to node that contains the record
840 Result: - number of bytes of free space in the node.
841 -------------------------------------------------------------------------------*/
843 u_int16_t
GetNodeFreeSize (BTreeControlBlockPtr btreePtr
, NodeDescPtr node
)
845 u_int16_t freeOffset
;
847 freeOffset
= GetRecordOffset (btreePtr
, node
, node
->numRecords
); //\80\80 inline?
849 return btreePtr
->nodeSize
- freeOffset
- (node
->numRecords
<< 1) - kOffsetSize
;
854 /*-------------------------------------------------------------------------------
856 Routine: GetRecordOffset - Return the offset for record "index".
860 Input: btreePtr - pointer to BTree control block
861 node - pointer to node that contains the record
862 index - record to obtain offset for
864 Result: - offset (in bytes) from beginning of node of record specified by index
865 -------------------------------------------------------------------------------*/
866 // make this a macro (for inlining)
868 u_int16_t
GetRecordOffset (BTreeControlBlockPtr btreePtr
,
875 pos
= (u_int8_t
*)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
;
877 return *(short *)pos
;
883 /*-------------------------------------------------------------------------------
885 Routine: GetRecordAddress - Return address of record "index".
889 Input: btreePtr - pointer to BTree control block
890 node - pointer to node that contains the record
891 index - record to obtain offset address for
893 Result: - pointer to record "index".
894 -------------------------------------------------------------------------------*/
895 // make this a macro (for inlining)
897 u_int8_t
* GetRecordAddress (BTreeControlBlockPtr btreePtr
,
903 pos
= (u_int8_t
*)node
+ GetRecordOffset (btreePtr
, node
, index
);
911 /*-------------------------------------------------------------------------------
913 Routine: GetRecordSize - Return size of record "index".
917 Note: This does not work on the FreeSpace index!
919 Input: btreePtr - pointer to BTree control block
920 node - pointer to node that contains the record
921 index - record to obtain record size for
923 Result: - size of record "index".
924 -------------------------------------------------------------------------------*/
926 u_int16_t
GetRecordSize (BTreeControlBlockPtr btreePtr
,
932 pos
= (u_int16_t
*) ((Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) - kOffsetSize
);
934 return *(pos
-1) - *pos
;
939 /*-------------------------------------------------------------------------------
940 Routine: GetOffsetAddress - Return address of offset for record "index".
944 Input: btreePtr - pointer to BTree control block
945 node - pointer to node that contains the record
946 index - record to obtain offset address for
948 Result: - pointer to offset for record "index".
949 -------------------------------------------------------------------------------*/
951 u_int16_t
*GetOffsetAddress (BTreeControlBlockPtr btreePtr
,
957 pos
= (Ptr
)node
+ btreePtr
->nodeSize
- (index
<< 1) -2;
959 return (u_int16_t
*)pos
;
964 /*-------------------------------------------------------------------------------
965 Routine: GetChildNodeNum - Return child node number from index record "index".
967 Function: Returns the first u_int32_t stored after the key for record "index".
969 Assumes: The node is an Index Node.
970 The key.length stored at record "index" is ODD. //\80\80 change for variable length index keys
972 Input: btreePtr - pointer to BTree control block
973 node - pointer to node that contains the record
974 index - record to obtain child node number from
976 Result: - child node number from record "index".
977 -------------------------------------------------------------------------------*/
979 u_int32_t
GetChildNodeNum (BTreeControlBlockPtr btreePtr
,
985 pos
= GetRecordAddress (btreePtr
, nodePtr
, index
);
986 pos
+= CalcKeySize(btreePtr
, (BTreeKey
*) pos
); // key.length + size of length field
988 return *(u_int32_t
*)pos
;
993 /*-------------------------------------------------------------------------------
994 Routine: InsertOffset - Add an offset and adjust existing offsets by delta.
996 Function: Add an offset at 'index' by shifting 'index+1' through the last offset
997 and adjusting them by 'delta', the size of the record to be inserted.
998 The number of records contained in the node is also incremented.
1000 Input: btreePtr - pointer to BTree control block
1001 node - pointer to node
1002 index - index at which to insert record
1003 delta - size of record to be inserted
1006 -------------------------------------------------------------------------------*/
1008 void InsertOffset (BTreeControlBlockPtr btreePtr
,
1013 u_int16_t
*src
, *dst
;
1014 u_int16_t numOffsets
;
1016 src
= GetOffsetAddress (btreePtr
, node
, node
->numRecords
); // point to free offset
1017 dst
= src
- 1; // point to new offset
1018 numOffsets
= node
->numRecords
++ - index
; // subtract index & postincrement
1021 *dst
++ = *src
++ + delta
; // to tricky?
1022 } while (numOffsets
--);
1027 /*-------------------------------------------------------------------------------
1029 Routine: DeleteOffset - Delete an offset.
1031 Function: Delete the offset at 'index' by shifting 'index+1' through the last offset
1032 and adjusting them by the size of the record 'index'.
1033 The number of records contained in the node is also decremented.
1035 Input: btreePtr - pointer to BTree control block
1036 node - pointer to node
1037 index - index at which to delete record
1040 -------------------------------------------------------------------------------*/
1042 void DeleteOffset (BTreeControlBlockPtr btreePtr
,
1046 u_int16_t
*src
, *dst
;
1047 u_int16_t numOffsets
;
1050 dst
= GetOffsetAddress (btreePtr
, node
, index
);
1052 delta
= *src
- *dst
;
1053 numOffsets
= --node
->numRecords
- index
; // predecrement numRecords & subtract index
1055 while (numOffsets
--)
1057 *--dst
= *--src
- delta
; // work our way left