#include "access/metapage.h"
#include "storage/buf.h"
+#include "storage/bufmgr.h"
+#include "utils/memutils.h"
/*
* Initialize a relation metapage.
void
MetapageInit(Relation relation, Page page)
{
- RelationMetaPage meta;
+ RelationMetapage meta;
PageSetRelationMetapage(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;
+}
relation->rd_exclprocs = NULL;
relation->rd_exclstrats = NULL;
relation->rd_amcache = NULL;
+ relation->rd_metapage = NULL;
}
/*
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
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)
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));
/*
#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
* 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
#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 */
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
* 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)
* 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 */
#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 */
/* 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
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.