| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| /*------------------------------------------------------------------------- |
| * |
| * cdbvarblock.h |
| * A general data package that has variable-length item array that can be |
| * efficiently indexed once complete. |
| * |
| * The variable-length items are byte sized. |
| * |
| * Alignment: |
| * The first item will be aligned on an eight-byte (64 bit) boundary. |
| * If all items are a multiple or 8, 4, 2 in length n then they will |
| * be aligned on those multiples. If the items are any length, then |
| * the alignment is 1 byte. |
| * |
| * For efficient VarBlock making, the client is given a pointer directly |
| * into the VarBlock buffer and the client fills their items directly. |
| * |
| * Examples: |
| * |
| * #define MY_VARBLOCK_TEMP_SCRATCH_LEN 2000 |
| * |
| * // Make a VarBlock in the buffer from some records. |
| * VarBlockByteLen MakerExample( |
| * byte *buffer, VarBlockByteLen maxBufferLen, |
| * Records *records, int numRecords) |
| * { |
| * VarBlockMaker myVarBlockMaker; |
| * uint8 tempScratch [MY_VARBLOCK_TEMP_SCRATCH_LEN]; |
| * byte *item; |
| * |
| * VarBlockMakerInit( |
| * &myVarBlockMaker, |
| * buffer, |
| * maxBufferLen, |
| * tempScratch, |
| * MY_VARBLOCK_TEMP_SCRATCH_LEN); |
| * |
| * for (int i = 0; i < numRecords; i++) |
| * { |
| * item = VarBlockMakerGetNextItemPtr( |
| * &myVarBlockMaker, |
| * records[i].length); |
| * Assert(item != NULL); // Real code would deal with NULL |
| * // indicating VarBlock full... |
| * |
| * MemCpy(item,records[i].data,records[i].length); |
| * } |
| * |
| * return VarBlockMakerFinish(&myVarBlockMaker); |
| * } |
| * |
| * // Extract records out of VarBlock. |
| * void ReaderExample( |
| * byte *buffer, VarBlockByteLen bufferLen, |
| * Records *records, int *numRecords) |
| * { |
| * VarBlockReader myVarBlockReader; |
| * byte *item; |
| * |
| * VarBlockReaderInit( |
| * &myVarBlockReader, |
| * buffer, |
| * bufferLen); |
| * |
| * *numRecords = VarBlockReaderItemCount(&myVarBlockReader); |
| * |
| * for (int i = 0; i < *numRecords; i++) |
| * { |
| * item = VarBlockMakerGetNextItemPtr( |
| * &myVarBlockMaker, |
| * &records[i].length); |
| * Assert(item != NULL); |
| * |
| * // |
| * // Keep a pointer to each item. |
| * // |
| * records[i].data = item; |
| * } |
| * } |
| * |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #ifndef CDBVARBLOCK_H |
| #define CDBVARBLOCK_H |
| |
| #include "postgres.h" |
| |
| typedef int32 VarBlockByteLen; |
| typedef int32 VarBlockByteOffset; |
| |
| // ---------------------------------------------------------- |
| typedef enum VarBlockVersion |
| { |
| InitialVersion = 1 |
| } VarBlockVersion; |
| |
| typedef uint16 VarBlockByteOffset16; |
| |
| /* |
| * The VarBlockByteOffset24struct is designed to be 3 bytes long |
| * (it contains a 24-bit field) but a few compilers will pad it to |
| * four bytes. Rather than deal with the ambiguity of unpersuadable compilers, |
| * we try to use "VARBLOCK_BYTE_OFFSET_24_LEN" rather than |
| * "sizeof(VarBlockByteOffset24)" when computing on-disk sizes AND |
| * we DO NOT index arrays as the struct but calculate addesses and do byte |
| * moves. |
| */ |
| typedef struct VarBlockByteOffset24 |
| { |
| unsigned byteOffset24:24; |
| /* Medium style offsets. */ |
| |
| } VarBlockByteOffset24; |
| |
| #define VARBLOCK_BYTE_OFFSET_24_LEN 3 |
| |
| typedef struct VarBlockByteLen24 |
| { |
| unsigned byteLen24:24; |
| /* Medium style lengths. */ |
| } VarBlockByteLen24; |
| |
| |
| typedef struct VarBlockHeader |
| { |
| /* |
| * Can't seem to get this to pack nicely to 64 bits so the header is aligned |
| * on an 8 byte boundary, so go to bit shifting... |
| */ |
| |
| // unsigned offsetsAreSmall:1; |
| // /* True if the offsets are small and occupy 2 bytes. |
| // * Otherwise, the block is larger 3-byte offsets are |
| // * used. |
| // */ |
| // unsigned reserved:5; |
| // /* Reserved for future. */ |
| // VarBlockVersion version:2; |
| // /* Version number */ |
| // |
| // VarBlockByteLen24 itemLenSum; |
| // /* Offset to the item offset array. */ |
| // |
| // ----------------------------------------------------------------------------- |
| // unsigned moreReserved:8; |
| // /* Reserved for future. */ |
| // unsigned itemCount:24; |
| // /* Total number of items. 24-bits to we bit-pad |
| // * to a total of 64-bits. |
| // */ |
| |
| uint32 bytes_0_3; |
| uint32 bytes_4_7; |
| |
| } VarBlockHeader; |
| |
| #define VarBlockGet_offsetsAreSmall(h) ((h)->bytes_0_3>>31) |
| #define VarBlockGet_reserved(h) (((h)->bytes_0_3&0x7C000000)>>26) |
| #define VarBlockGet_version(h) (((h)->bytes_0_3&0x03000000)>>24) |
| #define VarBlockGet_itemLenSum(h) ((h)->bytes_0_3&0x00FFFFFF) |
| |
| #define VarBlockGet_moreReserved(h) (((h)->bytes_4_7&0xFF000000)>>24) |
| #define VarBlockGet_itemCount(h) ((h)->bytes_4_7&0x00FFFFFF) |
| |
| // For single bits, set or clear directly. Otherwise, use AND to clear field then OR to set. |
| #define VarBlockSet_offsetsAreSmall(h,e) {if(e)(h)->bytes_0_3|=0x80000000;else(h)->bytes_0_3&=0x7FFFFFFF;} |
| #define VarBlockSet_version(h,e) {(h)->bytes_0_3&=0xFCFFFFFF;(h)->bytes_0_3|=(0x03000000&((e)<<24));} |
| #define VarBlockSet_itemLenSum(h,e) {(h)->bytes_0_3&=0xFF000000;(h)->bytes_0_3|=(0x00FFFFFF&(e));} |
| |
| #define VarBlockSet_itemCount(h,e) {(h)->bytes_4_7&=0xFF000000;(h)->bytes_4_7|=(0x00FFFFFF&(e));} |
| |
| // Assume field is initially zero. |
| #define VarBlock_Init(h) {(h)->bytes_0_3=0;(h)->bytes_4_7=0;} |
| |
| #define VarBlockInit_offsetsAreSmall(h,e) {if(e)(h)->bytes_0_3|=0x80000000;} |
| #define VarBlockInit_version(h,e) {(h)->bytes_0_3|=(0x03000000&((e)<<24));} |
| #define VarBlockInit_itemLenSum(h,e) {(h)->bytes_0_3|=(0x00FFFFFF&(e));} |
| |
| #define VarBlockInit_itemCount(h,e) {(h)->bytes_4_7|=(0x00FFFFFF&(e));} |
| |
| #define VARBLOCK_HEADER_LEN sizeof(VarBlockHeader) |
| |
| // ---------------------------------------------------------- |
| |
| typedef struct VarBlockMaker |
| { |
| VarBlockHeader *header; |
| /* The buffer with the header at the beginning. */ |
| |
| VarBlockByteLen maxBufferLen; |
| /* The maximum amount of space that can be used |
| * for the VarBlock. |
| */ |
| |
| VarBlockByteLen currentItemLenSum; |
| /* The running sum of the item data lengths. */ |
| |
| uint8 *tempScratchSpace; |
| int tempScratchSpaceLen; |
| /* The scratch space where we will temporarily |
| * keep the item offsets while making the |
| * VarBlock. |
| */ |
| |
| uint8 *nextItemPtr; |
| /* Pointer in the buffer to the beginning of |
| * the next item. |
| */ |
| |
| uint8 *last2ByteOffsetPtr; |
| /* The boundary point where we need to switch |
| * from 2-byte offsets to 3-byte offsets. |
| */ |
| |
| int currentItemCount; |
| /* The running count of items. */ |
| |
| int maxItemCount; |
| /* The maximum number of items for the VarBlock. |
| * Based on the length of the scratch area. |
| */ |
| } VarBlockMaker; |
| |
| // ---------------------------------------------------------- |
| |
| typedef struct VarBlockReader |
| { |
| VarBlockHeader *header; |
| /* The buffer with the header at the beginning. */ |
| |
| VarBlockByteLen bufferLen; |
| /* The exact byte length of this VarBlock. */ |
| |
| int nextIndex; |
| uint8 *nextItemPtr; |
| /* The index and pointer when doing get-next |
| * scanning of the VarBlock. |
| */ |
| |
| VarBlockByteOffset offsetToOffsetArray; |
| /* Offset to the beginning of the offset array. */ |
| |
| } VarBlockReader; |
| |
| |
| typedef enum VarBlockCheckError |
| { |
| VarBlockCheckOk = 0, |
| VarBlockCheckBadVersion, |
| VarBlockCheckReservedNot0, |
| VarBlockCheckMoreReservedNot0, |
| VarBlockCheckItemSumLenBad1, |
| VarBlockCheckItemSumLenBad2, |
| VarBlockCheckZeroPadBad1, |
| VarBlockCheckZeroPadBad2, |
| VarBlockCheckItemCountBad1, |
| VarBlockCheckItemCountBad2, |
| VarBlockCheckOffsetBad1, |
| VarBlockCheckOffsetBad2, |
| VarBlockCheckOffsetBad3, |
| } VarBlockCheckError; |
| |
| |
| /* |
| * Initialize the VarBlock maker. |
| * |
| * Since we are going to pack the item offset array |
| * right after the variable-length item array when |
| * finished, we need a place to buffer the |
| * offsets while we are making the block. The caller |
| * supplies the tempItemOffsets parameter for this |
| * purpose. Note that maxTempItemOffsets in effect |
| * serves as the maximum number of items. |
| */ |
| extern void VarBlockMakerInit( |
| VarBlockMaker *varBlockMaker, |
| uint8 *buffer, |
| VarBlockByteLen maxBufferLen, |
| uint8 *tempScratchSpace, |
| int tempScratchSpaceLen); |
| |
| /* |
| * Get a pointer to the next variable-length item so it can |
| * be filled in. |
| * |
| * Returns NULL when there is no more space left in the VarBlock. |
| */ |
| extern uint8* VarBlockMakerGetNextItemPtr( |
| VarBlockMaker *varBlockMaker, |
| VarBlockByteLen itemLen); |
| |
| /* |
| * Get the variable-length item count. |
| */ |
| extern int VarBlockMakerItemCount( |
| VarBlockMaker *varBlockMaker); |
| |
| /* |
| * Finish making the VarBlock. |
| * |
| * The item-offsets array will be added to the end. |
| */ |
| extern VarBlockByteLen VarBlockMakerFinish( |
| VarBlockMaker *varBlockMaker); |
| |
| /* |
| * Reset the VarBlock maker so it can make another one |
| * using the same inputs as given to VarBlockMakerInit. |
| */ |
| extern void VarBlockMakerReset( |
| VarBlockMaker *varBlockMaker); |
| |
| // ----------------------------------------------------------------------------- |
| |
| /* |
| * Determine if the header looks valid. |
| * |
| * peekLen must be at least VARBLOCK_HEADER_LEN bytes. |
| */ |
| extern VarBlockCheckError VarBlockHeaderIsValid( |
| uint8 *buffer, |
| VarBlockByteLen peekLen); |
| |
| /* |
| * Determine if the whole VarBlock looks valid. |
| * |
| * bufferLen must be VarBlock length. |
| */ |
| extern VarBlockCheckError VarBlockIsValid( |
| uint8 *buffer, |
| VarBlockByteLen bufferLen); |
| |
| /* |
| * Return a string message for the last check error. |
| */ |
| char *VarBlockGetCheckErrorStr(void); |
| |
| /* |
| * Given a pointer to a VarBlock with at least VARBLOCK_HEADER_LEN bytes |
| * present, return the length of the whole block. |
| */ |
| VarBlockByteLen VarBlockLenFromHeader( |
| uint8 *buffer, |
| VarBlockByteLen peekLen); |
| |
| // ----------------------------------------------------------------------------- |
| |
| /* |
| * Initialize the VarBlock reader. |
| */ |
| extern void VarBlockReaderInit( |
| VarBlockReader *varBlockReader, |
| uint8 *buffer, |
| VarBlockByteLen bufferLen); |
| |
| /* |
| * Set the position to a variable-length item. |
| * |
| * The next call to VarBlockReaderGetNextItemPtr will |
| * get the specified item. |
| */ |
| extern void VarBlockReaderPosition( |
| VarBlockReader *varBlockReader, |
| int itemIndex); |
| |
| /* |
| * Get a pointer to the next variable-length item. |
| * |
| * Returns NULL when there are no more items. |
| */ |
| extern uint8* VarBlockReaderGetNextItemPtr( |
| VarBlockReader *varBlockReader, |
| VarBlockByteLen *itemLen); |
| |
| /* |
| * Get the variable-length item count. |
| */ |
| extern int VarBlockReaderItemCount( |
| VarBlockReader *varBlockReader); |
| |
| /* |
| * Get a pointer to a variable-length item. |
| */ |
| extern uint8* VarBlockReaderGetItemPtr( |
| VarBlockReader *varBlockReader, |
| int itemIndex, |
| VarBlockByteLen *itemLen); |
| |
| extern VarBlockByteLen VarBlockCollapseToSingleItem( |
| uint8 *target, |
| uint8 *source, |
| int32 sourceLen); |
| |
| #endif /* CDBVARBLOCK_H */ |
| |