blob: bfd64bbaa0eb9943a194eb43b8222722cb22bcb9 [file] [log] [blame]
/*
* 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 */