diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out
index 67b103add3..7f92249c72 100644
--- a/contrib/pageinspect/expected/btree.out
+++ b/contrib/pageinspect/expected/btree.out
@@ -21,7 +21,7 @@ live_items    | 1
 dead_items    | 0
 avg_item_size | 16
 page_size     | 8192
-free_size     | 8128
+free_size     | 8132
 btpo_prev     | 0
 btpo_next     | 0
 btpo          | 0
diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out
index 5edb650085..60780b4bf7 100644
--- a/contrib/pageinspect/expected/page.out
+++ b/contrib/pageinspect/expected/page.out
@@ -65,19 +65,19 @@ SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bi
 SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
  fsm_page_contents 
 -------------------
- 0: 254           +
- 1: 254           +
- 3: 254           +
- 7: 254           +
- 15: 254          +
- 31: 254          +
- 63: 254          +
- 127: 254         +
- 255: 254         +
- 511: 254         +
- 1023: 254        +
- 2047: 254        +
- 4095: 254        +
+ 0: 253           +
+ 1: 253           +
+ 3: 253           +
+ 7: 253           +
+ 15: 253          +
+ 31: 253          +
+ 63: 253          +
+ 127: 253         +
+ 255: 253         +
+ 511: 253         +
+ 1023: 253        +
+ 2047: 253        +
+ 4095: 253        +
  fp_next_slot: 0  +
  
 (1 row)
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 3d4d4f6f93..4b3deb3f66 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -270,7 +270,24 @@ page_header(PG_FUNCTION_ARGS)
 	values[5] = UInt16GetDatum(page->pd_special);
 	values[6] = UInt16GetDatum(PageGetPageSize(page));
 	values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
-	values[8] = TransactionIdGetDatum(page->pd_prune_xid);
+	if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HeapPageSpecialData)))
+	{
+		HeapPageSpecial	pageSpecial = HeapPageGetSpecial(page);
+		if (pageSpecial->pd_magic == HEAP_PAGE_MAGIC ||
+			pageSpecial->pd_magic == SEQ_PAGE_MAGIC)
+		{
+			values[8] = TransactionIdGetDatum(pageSpecial->pd_prune_xid);
+			nulls[8] = false;
+		}
+		else
+		{
+			nulls[8] = true;
+		}
+	}
+	else
+	{
+		nulls[8] = true;
+	}
 
 	/* Build and return the tuple. */
 
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 75317b96a2..e8ac837236 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -620,7 +620,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
 	metap = HashPageGetMeta(BufferGetPage(metabuf));
 	stats.version = metap->hashm_version;
-	stats.space_per_page = metap->hashm_bsize;
+	stats.space_per_page = BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(HashPageOpaqueData));
 	_hash_relbuf(rel, metabuf);
 
 	/* Get the current relation length */
diff --git a/src/backend/access/common/bufmask.c b/src/backend/access/common/bufmask.c
index 57021f6ca1..d3808daaa1 100644
--- a/src/backend/access/common/bufmask.c
+++ b/src/backend/access/common/bufmask.c
@@ -45,11 +45,6 @@ mask_page_lsn_and_checksum(Page page)
 void
 mask_page_hint_bits(Page page)
 {
-	PageHeader	phdr = (PageHeader) page;
-
-	/* Ignore prune_xid (it's like a hint-bit) */
-	phdr->pd_prune_xid = MASK_MARKER;
-
 	/* Ignore PD_PAGE_FULL and PD_HAS_FREE_LINES flags, they are just hints. */
 	PageClearFull(page);
 	PageClearHasFreeLinePointers(page);
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index dbc8f2d6c7..b061d2de85 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8426,7 +8426,8 @@ heap_xlog_insert(XLogReaderState *record)
 	{
 		buffer = XLogInitBufferForRedo(record, 0);
 		page = BufferGetPage(buffer);
-		PageInit(page, BufferGetPageSize(buffer), 0);
+		PageInit(page, BufferGetPageSize(buffer), sizeof(HeapPageSpecialData));
+		HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 		action = BLK_NEEDS_REDO;
 	}
 	else
@@ -8542,7 +8543,8 @@ heap_xlog_multi_insert(XLogReaderState *record)
 	{
 		buffer = XLogInitBufferForRedo(record, 0);
 		page = BufferGetPage(buffer);
-		PageInit(page, BufferGetPageSize(buffer), 0);
+		PageInit(page, BufferGetPageSize(buffer), sizeof(HeapPageSpecialData));
+		HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 		action = BLK_NEEDS_REDO;
 	}
 	else
@@ -8756,7 +8758,8 @@ heap_xlog_update(XLogReaderState *record, bool hot_update)
 	{
 		nbuffer = XLogInitBufferForRedo(record, 0);
 		page = (Page) BufferGetPage(nbuffer);
-		PageInit(page, BufferGetPageSize(nbuffer), 0);
+		PageInit(page, BufferGetPageSize(nbuffer), sizeof(HeapPageSpecialData));
+		HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 		newaction = BLK_NEEDS_REDO;
 	}
 	else
@@ -9243,6 +9246,10 @@ heap_mask(char *pagedata, BlockNumber blkno)
 	mask_page_lsn_and_checksum(page);
 
 	mask_page_hint_bits(page);
+
+	/* Ignore prune_xid (it's like a hint-bit) */
+	HeapPageGetSpecial(page)->pd_prune_xid = InvalidTransactionId;
+
 	mask_unused_space(page);
 
 	for (off = 1; off <= PageGetMaxOffsetNumber(page); off++)
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 0d7bc68339..cc7d2c36cf 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -206,7 +206,8 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate)
 		/* Extend by one page. */
 		LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 		page = BufferGetPage(buffer);
-		PageInit(page, BufferGetPageSize(buffer), 0);
+		PageInit(page, BufferGetPageSize(buffer), sizeof(HeapPageSpecialData));
+		HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 		MarkBufferDirty(buffer);
 		blockNum = BufferGetBlockNumber(buffer);
 		freespace = PageGetHeapFreeSpace(page);
@@ -590,7 +591,8 @@ loop:
 			 BufferGetBlockNumber(buffer),
 			 RelationGetRelationName(relation));
 
-	PageInit(page, BufferGetPageSize(buffer), 0);
+	PageInit(page, BufferGetPageSize(buffer), sizeof(HeapPageSpecialData));
+	HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 
 	if (len > PageGetHeapFreeSpace(page))
 	{
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index f67d7d15df..2620a3a1c5 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -245,7 +245,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
 		 * Update the page's pd_prune_xid field to either zero, or the lowest
 		 * XID of any soon-prunable tuple.
 		 */
-		((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
+		HeapPageGetSpecial(page)->pd_prune_xid = prstate.new_prune_xid;
 
 		/*
 		 * Also clear the "page is full" flag, since there's no point in
@@ -283,10 +283,10 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
 		 * point in repeating the prune/defrag process until something else
 		 * happens to the page.
 		 */
-		if (((PageHeader) page)->pd_prune_xid != prstate.new_prune_xid ||
+		if (HeapPageGetSpecial(page)->pd_prune_xid != prstate.new_prune_xid ||
 			PageIsFull(page))
 		{
-			((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
+			HeapPageGetSpecial(page)->pd_prune_xid = prstate.new_prune_xid;
 			PageClearFull(page);
 			MarkBufferDirtyHint(buffer, true);
 		}
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 7d466c2588..5a2b7eea68 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -711,7 +711,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
 	if (!state->rs_buffer_valid)
 	{
 		/* Initialize a new empty page */
-		PageInit(page, BLCKSZ, 0);
+		PageInit(page, BLCKSZ, sizeof(HeapPageSpecialData));
+		HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 		state->rs_buffer_valid = true;
 	}
 
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ef3ca8c00b..a770423a15 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -53,16 +53,6 @@
  */
 #define SEQ_LOG_VALS	32
 
-/*
- * The "special area" of a sequence's buffer page looks like this.
- */
-#define SEQ_MAGIC	  0x1717
-
-typedef struct sequence_magic
-{
-	uint32		magic;
-} sequence_magic;
-
 /*
  * We store a SeqTable item for every sequence we have touched in the current
  * session.  This is needed to hold onto nextval/currval state.  (We can't
@@ -336,10 +326,9 @@ ResetSequence(Oid seq_relid)
 static void
 fill_seq_with_data(Relation rel, HeapTuple tuple)
 {
-	Buffer		buf;
-	Page		page;
-	sequence_magic *sm;
-	OffsetNumber offnum;
+	Buffer			buf;
+	Page			page;
+	OffsetNumber	offnum;
 
 	/* Initialize first page of relation with special magic number */
 
@@ -348,9 +337,8 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 
 	page = BufferGetPage(buf);
 
-	PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic));
-	sm = (sequence_magic *) PageGetSpecialPointer(page);
-	sm->magic = SEQ_MAGIC;
+	PageInit(page, BufferGetPageSize(buf), sizeof(HeapPageSpecialData));
+	HeapPageGetSpecial(page)->pd_magic = SEQ_PAGE_MAGIC;
 
 	/* Now insert sequence tuple */
 
@@ -1161,18 +1149,18 @@ read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
 {
 	Page		page;
 	ItemId		lp;
-	sequence_magic *sm;
+	HeapPageSpecial pageSpecial;
 	Form_pg_sequence_data seq;
 
 	*buf = ReadBuffer(rel, 0);
 	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
 
 	page = BufferGetPage(*buf);
-	sm = (sequence_magic *) PageGetSpecialPointer(page);
+	pageSpecial = HeapPageGetSpecial(page);
 
-	if (sm->magic != SEQ_MAGIC)
+	if (pageSpecial->pd_magic != SEQ_PAGE_MAGIC)
 		elog(ERROR, "bad magic number in sequence \"%s\": %08X",
-			 RelationGetRelationName(rel), sm->magic);
+			 RelationGetRelationName(rel), pageSpecial->pd_magic);
 
 	lp = PageGetItemId(page, FirstOffsetNumber);
 	Assert(ItemIdIsNormal(lp));
@@ -1873,7 +1861,6 @@ seq_redo(XLogReaderState *record)
 	char	   *item;
 	Size		itemsz;
 	xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
-	sequence_magic *sm;
 
 	if (info != XLOG_SEQ_LOG)
 		elog(PANIC, "seq_redo: unknown op code %u", info);
@@ -1892,9 +1879,8 @@ seq_redo(XLogReaderState *record)
 	 */
 	localpage = (Page) palloc(BufferGetPageSize(buffer));
 
-	PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic));
-	sm = (sequence_magic *) PageGetSpecialPointer(localpage);
-	sm->magic = SEQ_MAGIC;
+	PageInit(localpage, BufferGetPageSize(buffer), sizeof(HeapPageSpecialData));
+	HeapPageGetSpecial(page)->pd_magic = SEQ_PAGE_MAGIC;
 
 	item = (char *) xlrec + sizeof(xl_seq_rec);
 	itemsz = XLogRecGetDataLen(record) - sizeof(xl_seq_rec);
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index cf7f5e1162..90ca4769c7 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -870,7 +870,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
 				ereport(WARNING,
 						(errmsg("relation \"%s\" page %u is uninitialized --- fixing",
 								relname, blkno)));
-				PageInit(page, BufferGetPageSize(buf), 0);
+				PageInit(page, BufferGetPageSize(buf), sizeof(HeapPageSpecialData));
+				HeapPageGetSpecial(page)->pd_magic = HEAP_PAGE_MAGIC;
 				empty_pages++;
 			}
 			freespace = PageGetHeapFreeSpace(page);
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index dfbda5458f..98ec6abd82 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -55,7 +55,6 @@ PageInit(Page page, Size pageSize, Size specialSize)
 	p->pd_upper = pageSize - specialSize;
 	p->pd_special = pageSize - specialSize;
 	PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION);
-	/* p->pd_prune_xid = InvalidTransactionId;		done by above MemSet */
 }
 
 
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index 85dd10c45a..af08a9afa3 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -110,7 +110,6 @@ typedef struct
  *		pd_upper	- offset to end of free space.
  *		pd_special	- offset to start of special space.
  *		pd_pagesize_version - size in bytes and page layout version number.
- *		pd_prune_xid - oldest XID among potentially prunable tuples on page.
  *
  * The LSN is used by the buffer manager to enforce the basic rule of WAL:
  * "thou shalt write xlog before data".  A dirty buffer cannot be dumped
@@ -127,9 +126,6 @@ typedef struct
  * of relying on the page contents to decide whether to verify it. Hence
  * there are no flag bits relating to checksums.
  *
- * pd_prune_xid is a hint field that helps determine whether pruning will be
- * useful.  It is currently unused in index pages.
- *
  * The page version number and page size are packed together into a single
  * uint16 field.  This is for historical reasons: before PostgreSQL 7.3,
  * there was no concept of a page version number, and doing it this way
@@ -155,12 +151,47 @@ typedef struct PageHeaderData
 	LocationIndex pd_upper;		/* offset to end of free space */
 	LocationIndex pd_special;	/* offset to start of special space */
 	uint16		pd_pagesize_version;
-	TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
 	ItemIdData	pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */
 } PageHeaderData;
 
 typedef PageHeaderData *PageHeader;
 
+/*
+ * HeapPageSpecialData -- data that stored at the end of each heap page.
+ *
+ *		pd_prune_xid - oldest XID among potentially prunable tuples on page.
+ *		pd_magic - magic number identifies type of page
+ *
+ * pd_prune_xid is a hint field that helps determine whether pruning will be
+ * useful.  It is currently unused in index pages.
+ *
+ * pd_magic allows identified an type of object heap page belongs to.
+ * Currently, heap page may belong to an regular table heap or sequence heap.
+ */
+typedef struct HeapPageSpecialData
+{
+	TransactionId		pd_prune_xid; /* oldest prunable XID, or zero if none */
+	uint32				pd_magic;	  /* magic number identifies type of page */
+} HeapPageSpecialData;
+
+/*
+ * Possible value for pd_magic field.
+ */
+#define HEAP_PAGE_MAGIC	(0x1010)	/* regular heap page */
+#define SEQ_PAGE_MAGIC	(0x1717)	/* sequence page */
+
+typedef HeapPageSpecialData *HeapPageSpecial;
+
+/*
+ * Get pointer to HeapPageSpecialData without using pd_special of the page
+ * (for the sake of speed) assuming all heap pages have same size of special
+ * data.
+ */
+#define HeapPageGetSpecial(page) ( \
+	AssertMacro(((PageHeader) page)->pd_special == BLCKSZ - MAXALIGN(sizeof(HeapPageSpecialData))), \
+	(HeapPageSpecial) ((Pointer) page + BLCKSZ - MAXALIGN(sizeof(HeapPageSpecialData))) \
+)
+
 /*
  * pd_flags contains the following flag bits.  Undefined bits are initialized
  * to zero and may be used in the future.
@@ -388,18 +419,18 @@ PageValidateSpecialPointer(Page page)
 #define PageIsPrunable(page, oldestxmin) \
 ( \
 	AssertMacro(TransactionIdIsNormal(oldestxmin)), \
-	TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) && \
-	TransactionIdPrecedes(((PageHeader) (page))->pd_prune_xid, oldestxmin) \
+	TransactionIdIsValid(HeapPageGetSpecial(page)->pd_prune_xid) && \
+	TransactionIdPrecedes(HeapPageGetSpecial(page)->pd_prune_xid, oldestxmin) \
 )
 #define PageSetPrunable(page, xid) \
 do { \
 	Assert(TransactionIdIsNormal(xid)); \
-	if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
-		TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
-		((PageHeader) (page))->pd_prune_xid = (xid); \
+	if (!TransactionIdIsValid(HeapPageGetSpecial(page)->pd_prune_xid) || \
+		TransactionIdPrecedes(xid, HeapPageGetSpecial(page)->pd_prune_xid)) \
+		HeapPageGetSpecial(page)->pd_prune_xid = (xid); \
 } while (0)
 #define PageClearPrunable(page) \
-	(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
+	(HeapPageGetSpecial(page)->pd_prune_xid = InvalidTransactionId)
 
 
 /* ----------------------------------------------------------------
