*
* relfilenode.h
* Physical access information for relations.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/storage/relfilenode.h
*
* -------------------------------------------------------------------------
*/
#ifndef RELFILENODE_H
#define RELFILENODE_H
#include "storage/backendid.h"
#include "storage/buf/block.h"
typedef enum {
HEAP_DISK = 0,
SEGMENT_PAGE,
INVALID_STORAGE
} StorageType;
* The physical storage of a relation consists of one or more forks. The
* main fork is always created, but in addition to that there can be
* additional forks for storing various metadata. ForkNumber is used when
* we need to refer to a specific fork in a relation.
*/
typedef int ForkNumber;
#define SEGMENT_EXT_8192_FORKNUM -8
#define SEGMENT_EXT_1024_FORKNUM -7
#define SEGMENT_EXT_128_FORKNUM -6
#define SEGMENT_EXT_8_FORKNUM -5
#define PAX_DFS_TRUNCATE_FORKNUM -4
#define PAX_DFS_FORKNUM -3
#define DFS_FORKNUM -2
#define InvalidForkNumber -1
#define MAIN_FORKNUM 0
#define FSM_FORKNUM 1
#define VISIBILITYMAP_FORKNUM 2
#define BCM_FORKNUM 3
#define INIT_FORKNUM 4
#define PCA_FORKNUM 5
#define PCD_FORKNUM 6
* NOTE: if you add a new fork, change MAX_FORKNUM below and update the
* forkNames array in catalog.c
*/
#define MAX_FORKNUM INIT_FORKNUM
* RelFileNode must provide all that we need to know to physically access
* a relation, with the exception of the backend ID, which can be provided
* separately. Note, however, that a "physical" relation is comprised of
* multiple files on the filesystem, as each fork is stored as a separate
* file, and each fork can be divided into multiple segments. See md.c.
*
* spcNode identifies the tablespace of the relation. It corresponds to
* pg_tablespace.oid.
*
* dbNode identifies the database of the relation. It is zero for
* "shared" relations (those common to all databases of a cluster).
* Nonzero dbNode values correspond to pg_database.oid.
*
* relNode identifies the specific relation. relNode corresponds to
* pg_class.relfilenode (NOT pg_class.oid, because we need to be able
* to assign new physical files to relations in some situations).
* Notice that relNode is only unique within a particular database.
*
* bucketNode identifies bucketid of the relation. 1) -1 means non-bucket
* relation with heap disk storage type , 2) 0~BUCKETDATALEN-1 means bucketid
* of a bucket relation, 3) BUCKETDATALEN means a non-bucket segment storage
* relation. Both 2) and 3) representing segment storage type.
*
* opt identifies compressed relation type, reference struct <RelFileCompressOption>.
* 1) zero means normal relation(non-compression),
* 2) otherwise means compressed relation.
*
* Note: spcNode must be GLOBALTABLESPACE_OID if and only if dbNode is
* zero. We support shared relations only in the "global" tablespace.
*
* Note: in pg_class we allow reltablespace == 0 to denote that the
* relation is stored in its database's "default" tablespace (as
* identified by pg_database.dattablespace). However this shorthand
* is NOT allowed in RelFileNode structs --- the real tablespace ID
* must be supplied when setting spcNode.
*
* Note: in pg_class, relfilenode can be zero to denote that the relation
* is a "mapped" relation, whose current true filenode number is available
* from relmapper.c. Again, this case is NOT allowed in RelFileNodes.
*
* Note: various places use RelFileNode in hashtable keys. Therefore,
* there *must not* be any unused padding bytes in this struct. That
* should be safe as long as all the fields are of type Oid.
*/
typedef struct RelFileNode {
Oid spcNode;
Oid dbNode;
Oid relNode;
int2 bucketNode;
uint2 opt;
} RelFileNode;
typedef struct RelFileNodeV2 {
Oid spcNode;
Oid dbNode;
Oid relNode;
int4 bucketNode;
} RelFileNodeV2;
#define IsSegmentFileNode(rnode) ((rnode).bucketNode > InvalidBktId && (rnode).spcNode != EXRTO_BLOCK_INFO_SPACE_OID)
#define IsHeapFileNode(rnode) (!IsSegmentFileNode(rnode))
#define IsSegmentPhysicalRelNode(rNode) (IsSegmentFileNode(rNode) && (rNode).relNode <= 5)
#define IsSegmentLogicalRelNode(rNode) (IsSegmentFileNode(rNode) && (rNode).relNode > 5)
#define IsBucketFileNode(rnode) ((rnode).bucketNode > InvalidBktId && (rnode).bucketNode < SegmentBktId)
#define DefaultFileNodeOpt 0
typedef struct RelFileNodeOld
{
Oid spcNode;
Oid dbNode;
Oid relNode;
} RelFileNodeOld;
#define RelFileNodeRelCopy(relFileNodeRel, relFileNode) \
do { \
(relFileNodeRel).spcNode = (relFileNode).spcNode; \
(relFileNodeRel).dbNode = (relFileNode).dbNode; \
(relFileNodeRel).relNode = (relFileNode).relNode; \
} while(0)
#define RelFileNodeCopy(relFileNode, relFileNodeRel, bucketid) \
do { \
(relFileNode).spcNode = (relFileNodeRel).spcNode; \
(relFileNode).dbNode = (relFileNodeRel).dbNode; \
(relFileNode).relNode = (relFileNodeRel).relNode; \
(relFileNode).bucketNode = (bucketid); \
(relFileNode).opt = 0; \
} while (0)
#define RelFileNodeV2Copy(relFileNodeV2, relFileNode) \
do { \
(relFileNodeV2).spcNode = (relFileNode).spcNode; \
(relFileNodeV2).dbNode = (relFileNode).dbNode; \
(relFileNodeV2).relNode = (relFileNode).relNode; \
(relFileNodeV2).bucketNode = (relFileNode).bucketNode; \
} while (0)
typedef struct RelFileNodeKey {
RelFileNode relfilenode;
int columnid;
} RelFileNodeKey;
typedef struct RelFileNodeKeyEntry {
RelFileNodeKey key;
int number;
} RelFileNodeKeyEntry;
* Augmenting a relfilenode with the backend ID provides all the information
* we need to locate the physical storage. The backend ID is InvalidBackendId
* for regular relations (those accessible to more than one backend), or the
* owning backend's ID for backend-local relations. Backend-local relations
* are always transient and removed in case of a database crash; they are
* never WAL-logged or fsync'd.
*/
typedef struct RelFileNodeBackend {
RelFileNode node;
BackendId backend;
} RelFileNodeBackend;
typedef enum StorageEngine { ROW_STORE = 0, COLUMN_STORE } StorageEngine;
#define IsSupportSE(se) (ROW_STORE <= se && se <= COLUMN_STORE)
typedef struct RelFileNodeForkNum {
RelFileNodeBackend rnode;
BlockNumber segno;
ForkNumber forknumber;
StorageEngine storage;
} RelFileNodeForkNum;
#define RelFileNodeBackendIsTemp(rnode) ((rnode).backend != InvalidBackendId)
* Note: RelFileNodeEquals and RelFileNodeBackendEquals compare relNode first
* since that is most likely to be different in two unequal RelFileNodes. It
* is probably redundant to compare spcNode if the other fields are found equal,
* but do it anyway to be sure. Likewise for checking the backend ID in
* RelFileNodeBackendEquals.
*/
#define RelFileNodeEquals(node1, node2) \
((node1).relNode == (node2).relNode && (node1).dbNode == (node2).dbNode && (node1).spcNode == (node2).spcNode && \
(node1).bucketNode == (node2).bucketNode)
#define RelFileColumnNodeRelEquals(node1, node2) \
((node1).relNode == (node2).relNode && \
(node1).dbNode == (node2).dbNode && \
(node1).spcNode == (node2).spcNode)
#define RelFileNodeRelEquals(node1, node2) \
((node1).relNode == (node2).relNode && \
(node1).dbNode == (node2).dbNode && \
(node1).spcNode == (node2).spcNode)
#define RelFileNodeBackendEquals(node1, node2) \
((node1).node.relNode == (node2).node.relNode && (node1).node.dbNode == (node2).node.dbNode && \
(node1).backend == (node2).backend && (node1).node.spcNode == (node2).node.spcNode && \
(node1).node.bucketNode == (node2).node.bucketNode)
#define FirstColForkNum (MAX_FORKNUM)
#define IsValidColForkNum(forkNum) ((forkNum) > FirstColForkNum)
#define IsValidDfsForkNum(forkNum) ((forkNum) == DFS_FORKNUM)
#define IsValidPaxDfsForkNum(forkNum) ((forkNum) == PAX_DFS_FORKNUM)
#define IsTruncateDfsForkNum(forkNum) ((forkNum) == PAX_DFS_TRUNCATE_FORKNUM)
#define ColForkNum2ColumnId(forkNum) (AssertMacro(IsValidColForkNum(forkNum)), ((forkNum)-FirstColForkNum))
#define ColumnId2ColForkNum(attid) (AssertMacro(AttrNumberIsForUserDefinedAttr(attid)), (FirstColForkNum + (attid)))
#define GetColumnNum(forkNum) (IsValidColForkNum(forkNum) ? ColForkNum2ColumnId(forkNum) : 0)
typedef struct {
RelFileNode filenode;
ForkNumber forknum;
Oid ownerid;
} ColFileNode;
typedef struct {
RelFileNodeOld filenode;
ForkNumber forknum;
Oid ownerid;
} ColFileNodeRel;
#define SIZE_OF_COLFILENODE(compress) ((compress) ? sizeof(ColFileNode) : sizeof(ColFileNodeRel))
* 1) ForkNumber type must be 32-bit;
* 2) forknum value occupies the lower 16-bit;
* 3) bucketid value occupies the upper 16-bit;
* If the upper three condition changes, please consider this function again.
*/
static inline void forknum_add_bucketid(ForkNumber& forknum, int4 bucketid)
{
forknum = (ForkNumber)(((uint2)forknum) | (((uint2)(bucketid + 1)) << 16));
}
* 1) converse ForkNumber to uint to make sure logic right-shift
* 2) converse the logic-right-shift result to int2 to ensure the negative bucketid value
*/
static inline int4 forknum_get_bucketid(const ForkNumber& forknum)
{
return (int2)((((uint)forknum >> 16) & 0xffff) - 1);
}
* 1) converse ForkNumber to uint to make sure the bit-operation safe
* 2) converse the lower 16-bit to int2 to ensure the negative forknum
*/
static inline ForkNumber forknum_get_forknum(const ForkNumber& forknum)
{
return (int2)((uint)forknum & 0xffff);
}
* 1) converse ForkNumber to uint to make sure the bit-operation safe
* 2) converse the lower 16-bit to int2 to ensure the negative forknum
*/
static inline StorageType forknum_get_storage_type(const ForkNumber& forknum)
{
return (StorageType)(((uint)forknum & 0xC000) >> 14);
}
#define ColFileNodeCopy(colFileNode, colFileNodeRel) \
do { \
(colFileNode)->filenode.spcNode = (colFileNodeRel)->filenode.spcNode; \
(colFileNode)->filenode.dbNode = (colFileNodeRel)->filenode.dbNode; \
(colFileNode)->filenode.relNode = (colFileNodeRel)->filenode.relNode; \
(colFileNode)->filenode.opt = 0; \
(colFileNode)->filenode.bucketNode = (int2)forknum_get_bucketid((colFileNodeRel)->forknum); \
(colFileNode)->forknum = forknum_get_forknum((colFileNodeRel)->forknum); \
(colFileNode)->ownerid = (colFileNodeRel)->ownerid; \
} while (0)
#define ColFileNodeFullCopy(colFileNode, colFileNode2) \
do { \
(colFileNode)->filenode.spcNode = (colFileNode2)->filenode.spcNode; \
(colFileNode)->filenode.dbNode = (colFileNode2)->filenode.dbNode; \
(colFileNode)->filenode.relNode = (colFileNode2)->filenode.relNode; \
(colFileNode)->filenode.bucketNode = (int2)forknum_get_bucketid((colFileNode2)->forknum); \
(colFileNode)->forknum = forknum_get_forknum((colFileNode2)->forknum); \
(colFileNode)->filenode.opt = (colFileNode2)->filenode.opt; \
(colFileNode)->ownerid = (colFileNode2)->ownerid; \
} while (0)
#endif