/* ------------------------------------------------------------------------- * * 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 // used for data file cache, you can modify than as you like #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 . * 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; /* tablespace */ Oid dbNode; /* database */ Oid relNode; /* relation */ int2 bucketNode; /* bucketid */ uint2 opt; } RelFileNode; typedef struct RelFileNodeV2 { Oid spcNode; /* tablespace */ Oid dbNode; /* database */ Oid relNode; /* relation */ int4 bucketNode; /* bucketid */ } 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 /*RelFileNodeOld: Old version relfilenode. Compatible with older versions of relfilenode.*/ typedef struct RelFileNodeOld { Oid spcNode; /* tablespace */ Oid dbNode; /* database */ Oid relNode; /* relation */ } 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) /*This struct used for remove duplicated file list where we scan part of BCM files*/ typedef struct RelFileNodeKey { RelFileNode relfilenode; /*relfilenode*/ int columnid; /*column for CU store*/ } RelFileNodeKey; typedef struct RelFileNodeKeyEntry { RelFileNodeKey key; int number; /*Times the relfilenode occurence*/ } 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) // key to identify data file // 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) // keep [MAX_FORKNUM, FirstColumnForkNum) unused. // try my best to reduce the effect on updating. #define FirstColForkNum (MAX_FORKNUM) // ColForkNum include column id information // #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))) // fetch column number from forknum given. #define GetColumnNum(forkNum) (IsValidColForkNum(forkNum) ? ColForkNum2ColumnId(forkNum) : 0) typedef struct { RelFileNode filenode; // for row table, *forknum* <= MAX_FORKNUM. // for column table, *forknum* > FirstColForkNum. ForkNumber forknum; // relation's owner id Oid ownerid; } ColFileNode; typedef struct { RelFileNodeOld filenode; // for row table, *forknum* <= MAX_FORKNUM. // for column table, *forknum* > FirstColForkNum. ForkNumber forknum; // relation's owner id 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 /* RELFILENODE_H */