--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * metapage.c
+ * Generic relation metapage support.
+ *
+ * Prior to PostgreSQL 9.3, some relation types (heap, gist) had no
+ * metapage at all, while others (btree, gin, hash, spgist) had only an
+ * access-method specific metapage. Beginning in PostgreSQL 9.3, all
+ * relations have a metapage. We reserve the first 512 bytes of each
+ * metablock for the page header and generic metadata that applies to all
+ * relation types; the remainder of the page may be used by each individual
+ * access method for its own purposes.
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/access/common/heaptuple.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <time.h>
+
+#include "access/metapage.h"
+#include "storage/buf.h"
+
+/*
+ * Initialize a relation metapage.
+ */
+void
+MetapageInit(Relation relation, Page page)
+{
+ RelationMetaPage meta;
+
+ PageSetRelationMetapage(page);
+
+ meta = BlindGetRelationMeta(page);
+ meta->rmp_magic = METAPAGE_MAGIC;
+ meta->rmp_version = METAPAGE_VERSION;
+ 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_creation_time = (pg_time_t) time(NULL);
+ meta->rmp_rewrite_time = meta->rmp_creation_time;
+ meta->rmp_flags = 0;
+ meta->rmp_minlayout = PG_PAGE_LAYOUT_VERSION;
+ meta->rmp_maxlayout = PG_PAGE_LAYOUT_VERSION;
+}
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * metapage.h
+ * Generic relation metapage support.
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/access/metapage.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef METAPAGE_H
+#define METAPAGE_H
+
+#include "pgtime.h"
+#include "storage/bufpage.h"
+#include "utils/rel.h"
+
+#define METAPAGE_MAGIC 0x518f912a
+#define METAPAGE_VERSION 1
+
+/*
+ * 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
+{
+ uint32 rmp_magic; /* should contain METAPAGE_MAGIC */
+ uint32 rmp_version; /* should contain METAPAGE_VERSION */
+ Oid rmp_dboid; /* database OID */
+ Oid rmp_tsoid; /* tablespace OID */
+ Oid rmp_reloid; /* relation OID */
+ Oid rmp_relfilenode; /* relation relfilenode */
+ pg_time_t rmp_creation_time; /* time created, or 0 if unknown */
+ pg_time_t rmp_rewrite_time; /* last rewrite, or 0 if unknown */
+ uint32 rmp_flags; /* relation-level flag bits */
+ uint16 rmp_minlayout; /* oldest page layout version in rel */
+ uint16 rmp_maxlayout; /* newest page layout version in rel */
+} RelationMetaPageData;
+
+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
+ * placement of data on the page.
+ *
+ * Prior to the introduction of metapages for all relations, access methods
+ * that had metapages stored their private metadata at the offset where
+ * common metadata is now stored. Code that needs to read both old and new
+ * metapages can use GetAccessMethodMeta() to locate their data at whichever
+ * address it's stored, while code that knows it is looking at a new-format
+ * metapage can use BlindGetAccessMethodMeta() for efficiency.
+ */
+#define BlindGetRelationMeta(page) \
+ ((RelationMetaPage) PageGetContents((page)))
+#define ACCESS_METHOD_META_OFFSET 512
+#define BlindGetAccessMethodMeta(page) \
+ (((char *) (page)) + ACCESS_METHOD_META_OFFSET)
+#define GetRelationMeta(page) \
+ (PageIsRelationMetapage((page)) ? BlindGetRelationMeta((page)) : NULL)
+#define GetAccessMethodMeta(page)) \
+ (PageIsRelationMetapage((page)) ? BlindGetAccessMethodMeta((page)) \
+ : PageGetContents((page)))
+
+/*
+ * Function prototypes.
+ */
+extern void MetapageInit(Relation relation, Page page);
+
+#endif /* METAPAGE_H */
* tuple? */
#define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to
* everyone */
+#define PD_RELATION_METAPAGE 0x0008 /* page is a relation metapage */
-#define PD_VALID_FLAG_BITS 0x0007 /* OR of all valid pd_flags bits */
+#define PD_VALID_FLAG_BITS 0x000F /* OR of all valid pd_flags bits */
/*
* Page layout version number 0 is for pre-7.3 Postgres releases.
#define PageClearAllVisible(page) \
(((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE)
+#define PageIsRelationMetapage(page) \
+ (((PageHeader) (page))->pd_flags & PD_RELATION_METAPAGE)
+#define PageSetRelationMetapage(page) \
+ (((PageHeader) (page))->pd_flags |= PD_RELATION_METAPAGE)
+
#define PageIsPrunable(page, oldestxmin) \
( \
AssertMacro(TransactionIdIsNormal(oldestxmin)), \