/*-------------------------------------------------------------------------
 *
 * block.h--
 *    POSTGRES disk block definitions.
 *
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 * block.h,v 1.3 1995/04/09 20:27:27 andrew Exp
 *
 *-------------------------------------------------------------------------
 */
#ifndef	BLOCK_H
#define BLOCK_H

#include "c.h"

/*
 * each data file (heap or index) is divided into postgres disk blocks
 * (which may be thought of as the unit of i/o -- a postgres buffer
 * contains exactly one disk block).
 */
typedef uint32	BlockNumber;

#define InvalidBlockNumber	((BlockNumber) 0xFFFFFFFF)

/*
 * a postgres disk block can be any power-of-two size; the size of the
 * BlockSize type as well as practical limitations (the size of a
 * PageHeader and the minimal tuple size) currently limit the range of
 * valid sizes to 128B to 32KB.  (you can't really get anything useful
 * done with less than 512B so MinBlockSize is defined as 2^9.)
 *
 * the postgres buffer page code also reflects these limitations.
 */
typedef uint16	BlockSize;

#define	MinBlockSize		((BlockSize) (1 << 9))	/* just because */
#define MaxBlockSize		((BlockSize) (1 << 15))	/* 16 bit limit */

/*
 * BlockId is just a storage type for BlockNumber.  in other words,
 * this type is used for on-disk structures (e.g., HeapTuples) whereas
 * BlockNumber are the type on which calculations are performed (e.g.,
 * in access method code).
 *
 * there doesn't appear to be any reason to have separate types except
 * for the fact that BlockIds can be short-aligned (and therefore any
 * structures that contains them, such as ItemId and ItemPointer, can
 * also be short-aligned).  this is an important consideration for
 * reducing the space requirements of the line pointer array on each
 * page and the header of each tuple, so it doesn't seem wise to
 * change this without good reason.
 */
typedef struct BlockIdData {
    uint16	bi_hi;
    uint16	bi_lo;
} BlockIdData;

typedef BlockIdData	*BlockId;	/* block identifier */

/* ----------------
 *	support macros
 * ----------------
 */
/*
 * BlockSizeIsValid --
 *	True iff size is valid.
 *	should check that this is a power of 2
 */
#define BlockSizeIsValid(blockSize) \
    (((blockSize) >= MinBlockSize) && ((blockSize) <= MaxBlockSize))

/*
 * BlockNumberIsValid --
 *	True iff blockNumber is valid.
 */
#define BlockNumberIsValid(blockNumber) \
    ((bool) \
     (((blockNumber) >= 0) && ((int32) (blockNumber) != InvalidBlockNumber)))

/*
 * BlockIdIsValid --
 *	True iff the block identifier is valid.
 */
#define BlockIdIsValid(blockId) \
    ((bool) PointerIsValid(blockId))

/*
 * BlockIdSet --
 *	Sets a block identifier to the specified value.
 */
#define BlockIdSet(blockId, blockNumber) \
    Assert(PointerIsValid(blockId)); \
    (blockId)->bi_hi = (blockNumber) >> 16; \
    (blockId)->bi_lo = (blockNumber) & 0xffff

/*
 * BlockIdSetInvalid --
 *	Sets a block identifier to InvalidBlockNumber
 */
#define BlockIdSetInvalid(blockId) \
    Assert(PointerIsValid(blockId)); \
    (blockId)->bi_hi = 0xffff; \
    (blockId)->bi_lo = 0xffff

/*
 * BlockIdCopy --
 *	Copy a block identifier.
 */
#define BlockIdCopy(toBlockId, fromBlockId) \
    Assert(PointerIsValid(toBlockId)); \
    Assert(PointerIsValid(fromBlockId)); \
    (toBlockId)->bi_hi = (fromBlockId)->bi_hi; \
    (toBlockId)->bi_lo = (fromBlockId)->bi_lo

/*
 * BlockIdEquals --
 *	Check for block number equality.
 */
#define BlockIdEquals(blockId1, blockId2) \
    ((blockId1)->bi_hi == (blockId2)->bi_hi && \
     (blockId1)->bi_lo == (blockId2)->bi_lo)

/*
 * BlockIdGetBlockNumber --
 *	Retrieve the block number from a block identifier.
 */
#define BlockIdGetBlockNumber(blockId) \
    (AssertMacro(BlockIdIsValid(blockId)) ? \
     (BlockNumber) (((blockId)->bi_hi << 16) | ((uint16) (blockId)->bi_lo)) : \
     (BlockNumber) InvalidBlockNumber)

#endif	/* BLOCK_H */
