Access to metapage data.
authorRobert Haas <rhaas@postgresql.org>
Tue, 12 Jun 2012 19:24:35 +0000 (15:24 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 14 Jun 2012 14:33:05 +0000 (10:33 -0400)
src/backend/access/common/metapage.c
src/backend/utils/cache/relcache.c
src/include/access/gin_private.h
src/include/access/gist_private.h
src/include/access/metapage.h
src/include/access/nbtree.h
src/include/access/spgist_private.h
src/include/utils/rel.h

index 06033d8fb2197264ee45390131868615751b6975..3606a133ab91ad289c02a1f2ffa4926eb42b8c81 100644 (file)
@@ -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;
+}
index 2e6776e78f76a8b20467a144f9ebe98956b9da6a..b187a4ebf082d5ddb8c8483462d5252558a17e5b 100644 (file)
@@ -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));
 
                /*
index 5f336998af6de7f21d253c6cda631733965433ae..0df0a4c26f34b9238cc82361cd5bfd89bfca0c08 100644 (file)
@@ -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
index 142a30ec643f1cd486e4a2760438ae86adf13466..da68002430c229644b88dd7bc214e540c5c79e2e 100644 (file)
@@ -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
index aa1a4f35b8d437420a1fb166331c678d39ef01cc..5f7450036a09daf91c22b36ec5e983742cda6c0c 100644 (file)
 
 #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 */
index 78efad2d0001667870e94943d8ae71011182406d..dc20191e552579bf89815c9c3a525abab08255c7 100644 (file)
@@ -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 */
 
index 4fd20d49c3a0a66183a33f04bd08feb4b3018376..44b0c4fb660956cd2c0f16491accdbf9100f9546 100644 (file)
@@ -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
index 4669d8a67ef4298c591accbc81710c76e1efa535..8f7767924ef2dff10b42104b0251628adcfb20c0 100644 (file)
@@ -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.