From efc08df6bc5ea7b7588f3547b29ad6aecaab6fc0 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 12 Jun 2012 15:24:35 -0400 Subject: [PATCH] Access to metapage data. --- src/backend/access/common/metapage.c | 52 +++++++++++++++++++++++++++- src/backend/utils/cache/relcache.c | 9 +++++ src/include/access/gin_private.h | 2 +- src/include/access/gist_private.h | 2 +- src/include/access/metapage.h | 18 +++++++--- src/include/access/nbtree.h | 2 +- src/include/access/spgist_private.h | 2 +- src/include/utils/rel.h | 2 ++ 8 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/backend/access/common/metapage.c b/src/backend/access/common/metapage.c index 06033d8fb2..3606a133ab 100644 --- a/src/backend/access/common/metapage.c +++ b/src/backend/access/common/metapage.c @@ -27,6 +27,8 @@ #include "access/metapage.h" #include "storage/buf.h" +#include "storage/bufmgr.h" +#include "utils/memutils.h" /* * Initialize a relation metapage. @@ -34,7 +36,7 @@ void MetapageInit(Relation relation, Page page) { - RelationMetaPage meta; + RelationMetapage meta; PageSetRelationMetapage(page); @@ -50,3 +52,51 @@ MetapageInit(Relation relation, Page page) meta->rmp_maxlayout = PG_PAGE_LAYOUT_VERSION; meta->rmp_relfilenode_time = (pg_time_t) time(NULL); } + +/* + * Get metadata for a relation. + */ +RelationMetapage +RelationGetMetadata(Relation relation) +{ + Buffer buffer; + Page page; + RelationMetapage meta; + + /* If data is already cached, just return it. */ + if (relation->rd_metapage != NULL) + return relation->rd_metapage; + + /* Allocate memory for the data. */ + meta = (RelationMetapage) MemoryContextAllocZero(CacheMemoryContext, + sizeof(RelationMetapageData)); + + /* Read and metapage. */ + buffer = ReadBuffer(relation, METAPAGE_BLKNO); + page = BufferGetPage(buffer); + LockBuffer(buffer, BUFFER_LOCK_SHARE); + + /* Copy real metapage, or for backward compatibility, create a fake one. */ + if (PageIsRelationMetapage(page)) + { + memcpy(meta, BlindGetRelationMeta(page), sizeof(RelationMetapageData)); + UnlockReleaseBuffer(buffer); + } + { + UnlockReleaseBuffer(buffer); + meta->rmp_magic = METAPAGE_MAGIC; + meta->rmp_version = 0; /* fake metapage */ + meta->rmp_dboid = relation->rd_node.dbNode; + meta->rmp_tsoid = relation->rd_node.spcNode; + meta->rmp_reloid = RelationGetRelid(relation); + meta->rmp_relfilenode = relation->rd_node.relNode; + meta->rmp_flags = 0; + meta->rmp_minlayout = PG_PAGE_LAYOUT_VERSION; + meta->rmp_maxlayout = PG_PAGE_LAYOUT_VERSION; + meta->rmp_relfilenode_time = (pg_time_t) time(NULL); + } + + /* Cache result for next time, and return it. */ + relation->rd_metapage = meta; + return meta; +} diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2e6776e78f..b187a4ebf0 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1121,6 +1121,7 @@ RelationInitIndexAccessInfo(Relation relation) relation->rd_exclprocs = NULL; relation->rd_exclstrats = NULL; relation->rd_amcache = NULL; + relation->rd_metapage = NULL; } /* @@ -1675,6 +1676,11 @@ RelationReloadIndexInfo(Relation relation) pfree(relation->rd_amcache); relation->rd_amcache = NULL; + /* Must free any metapage upon relcache flush */ + if (relation->rd_metapage) + pfree(relation->rd_metapage); + relation->rd_metapage = NULL; + /* * If it's a shared index, we might be called before backend startup has * finished selecting a database, in which case we have no way to read @@ -1774,6 +1780,8 @@ RelationDestroyRelation(Relation relation) list_free(relation->rd_indexlist); bms_free(relation->rd_indexattr); FreeTriggerDesc(relation->trigdesc); + if (relation->rd_metapage) + pfree(relation->rd_metapage); if (relation->rd_options) pfree(relation->rd_options); if (relation->rd_indextuple) @@ -4194,6 +4202,7 @@ load_relcache_init_file(bool shared) rel->rd_createSubid = InvalidSubTransactionId; rel->rd_newRelfilenodeSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; + rel->rd_metapage = NULL; MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info)); /* diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 5f336998af..0df0a4c26f 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -51,7 +51,7 @@ typedef GinPageOpaqueData *GinPageOpaque; #define GIN_LIST_FULLROW (1 << 5) /* makes sense only on GIN_LIST page */ /* Page numbers of fixed-location pages */ -#define GIN_METAPAGE_BLKNO (0) +#define GIN_METAPAGE_BLKNO METAPAGE_BLKNO #define GIN_ROOT_BLKNO (1) typedef struct GinMetaPageData diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 142a30ec64..da68002430 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -290,7 +290,7 @@ typedef struct * metapage is at block 0, and it contains the location of the root block. */ #define GIST_OLD_ROOT_BLKNO 0 -#define GIST_METAPAGE_BLKNO 0 +#define GIST_METAPAGE_BLKNO METAPAGE_BLKNO /* * Before PostgreSQL 9.1, we used rely on so-called "invalid tuples" on inner diff --git a/src/include/access/metapage.h b/src/include/access/metapage.h index aa1a4f35b8..5f7450036a 100644 --- a/src/include/access/metapage.h +++ b/src/include/access/metapage.h @@ -19,13 +19,14 @@ #define METAPAGE_MAGIC 0x518f912a #define METAPAGE_VERSION 1 +#define METAPAGE_BLKNO 0 /* * Metadata that is common to all relation types. This information is stored * at the beginning of each page, following the page-header, at the address * returned by PageGetContents(). */ -typedef struct RelationMetaPageData +typedef struct RelationMetapageData { uint32 rmp_magic; /* should contain METAPAGE_MAGIC */ uint32 rmp_version; /* should contain METAPAGE_VERSION */ @@ -37,16 +38,16 @@ typedef struct RelationMetaPageData uint16 rmp_minlayout; /* oldest page layout version in rel */ uint16 rmp_maxlayout; /* newest page layout version in rel */ pg_time_t rmp_relfilenode_time; /* time relfilenode created */ -} RelationMetaPageData; +} RelationMetapageData; -typedef RelationMetaPageData *RelationMetaPage; +typedef RelationMetapageData *RelationMetapage; /* * Metadata that is specific to a particular access method is stored later * in the page, following the common metadata. In order to allow for future * expansion of the common metadata, we start the access-method specific * metadata 512 bytes from the beginning of the page. That way, future - * versions of RelationMetaPageData can be larger without affecting the + * versions of RelationMetapageData can be larger without affecting the * placement of data on the page. * * Prior to the introduction of metapages for all relations, access methods @@ -57,7 +58,7 @@ typedef RelationMetaPageData *RelationMetaPage; * metapage can use BlindGetAccessMethodMeta() for efficiency. */ #define BlindGetRelationMeta(page) \ - ((RelationMetaPage) PageGetContents((page))) + ((RelationMetapage) PageGetContents((page))) #define ACCESS_METHOD_META_OFFSET 512 #define BlindGetAccessMethodMeta(page) \ (((char *) (page)) + ACCESS_METHOD_META_OFFSET) @@ -71,5 +72,12 @@ typedef RelationMetaPageData *RelationMetaPage; * Function prototypes. */ extern void MetapageInit(Relation relation, Page page); +extern RelationMetapage RelationGetMetadata(Relation rel); + +/* + * Useful macros. + */ +#define RelationHasMetapage(relation) \ + (RelationGetMetadata((rel))->rmp_version != 0) #endif /* METAPAGE_H */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 78efad2d00..dc20191e55 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -105,7 +105,7 @@ typedef struct BTMetaPageData #define BTPageGetMeta(p) \ ((BTMetaPageData *) GetAccessMethodMeta(p)) -#define BTREE_METAPAGE 0 /* first page is meta */ +#define BTREE_METAPAGE METAPAGE_BLKNO #define BTREE_MAGIC 0x053162 /* magic number of btree pages */ #define BTREE_VERSION 2 /* current version number */ diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index 4fd20d49c3..44b0c4fb66 100644 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -22,7 +22,7 @@ /* Page numbers of fixed-location pages */ -#define SPGIST_METAPAGE_BLKNO (0) /* metapage */ +#define SPGIST_METAPAGE_BLKNO METAPAGE_BLKNO /* metapage */ #define SPGIST_ROOT_BLKNO (1) /* root for normal entries */ #define SPGIST_NULL_BLKNO (2) /* root for null-value entries */ #define SPGIST_LAST_FIXED_BLKNO SPGIST_NULL_BLKNO diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 4669d8a67e..8f7767924e 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -109,6 +109,8 @@ typedef struct RelationData RuleLock *rd_rules; /* rewrite rules */ MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ + /* use "struct" here to avoid needing to include metapage.h: */ + struct RelationMetapageData *rd_metapage; /* Relation metapage data */ /* * rd_options is set whenever rd_rel is loaded into the relcache entry. -- 2.39.5