diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 74c41fa..cd76158 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1945,6 +1945,16 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
 							ItemPointerGetBlockNumber(&(heaptup->t_self)),
 							vmbuffer);
 	}
+	else if (PageIsAllVisibleOrDead(BufferGetPage(buffer)))
+	{
+		/*
+		 * We don't need to worry about WAL-logging this action. The only place
+		 * where this flag is consulted is in the second phase of vacuum and
+		 * the first phase of vacuum will take care of clearing/setting the
+		 * flag appropriately
+		 */
+		PageClearAllVisibleOrDead(BufferGetPage(buffer));
+	}
 
 	/*
 	 * XXX Should we set PageSetPrunable on this page ?
@@ -2204,6 +2214,8 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
 								BufferGetBlockNumber(buffer),
 								vmbuffer);
 		}
+		else if (PageIsAllVisibleOrDead(page))
+			PageClearAllVisibleOrDead(page);
 
 		/*
 		 * XXX Should we set PageSetPrunable on this page ? See heap_insert()
@@ -2585,6 +2597,8 @@ l1:
 		visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
 							vmbuffer);
 	}
+	else if (PageIsAllVisibleOrDead(page))
+		PageClearAllVisibleOrDead(page);
 
 	/* store transaction information of xact deleting the tuple */
 	tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
@@ -3197,6 +3211,9 @@ l2:
 		visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
 							vmbuffer);
 	}
+	else if (PageIsAllVisibleOrDead(BufferGetPage(buffer)))
+		PageClearAllVisibleOrDead(BufferGetPage(buffer));
+
 	if (newbuf != buffer && PageIsAllVisible(BufferGetPage(newbuf)))
 	{
 		all_visible_cleared_new = true;
@@ -3204,6 +3221,8 @@ l2:
 		visibilitymap_clear(relation, BufferGetBlockNumber(newbuf),
 							vmbuffer_new);
 	}
+	else if (PageIsAllVisibleOrDead(BufferGetPage(newbuf)))
+		PageClearAllVisibleOrDead(BufferGetPage(newbuf));
 
 	if (newbuf != buffer)
 		MarkBufferDirty(newbuf);
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 97a2868..221ddf0 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -222,6 +222,13 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
 		((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
 
 		/*
+		 * If we don't find new prune xid, we assume that there is nothing more
+		 * do on the page and so clear the prunable flag
+		 */
+		if (!TransactionIdIsValid(prstate.new_prune_xid))
+			PageClearPrunable(page);
+
+		/*
 		 * Also clear the "page is full" flag, since there's no point in
 		 * repeating the prune/defrag process until something else happens to
 		 * the page.
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 5036849..ea9cfa5 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -458,6 +458,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		Size		freespace;
 		bool		all_visible_according_to_vm;
 		bool		all_visible;
+		bool		all_visible_or_dead;
 		bool		has_dead_tuples;
 		TransactionId visibility_cutoff_xid = InvalidTransactionId;
 
@@ -661,6 +662,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		 * requiring freezing.
 		 */
 		all_visible = true;
+		all_visible_or_dead = true;
 		has_dead_tuples = false;
 		nfrozen = 0;
 		hastup = false;
@@ -759,6 +761,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 						if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
 						{
 							all_visible = false;
+							all_visible_or_dead = false;
 							break;
 						}
 
@@ -770,6 +773,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 						if (!TransactionIdPrecedes(xmin, OldestXmin))
 						{
 							all_visible = false;
+							all_visible_or_dead = false;
 							break;
 						}
 
@@ -786,14 +790,17 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 					 */
 					nkeep += 1;
 					all_visible = false;
+					all_visible_or_dead = false;
 					break;
 				case HEAPTUPLE_INSERT_IN_PROGRESS:
 					/* This is an expected case during concurrent vacuum */
 					all_visible = false;
+					all_visible_or_dead = false;
 					break;
 				case HEAPTUPLE_DELETE_IN_PROGRESS:
 					/* This is an expected case during concurrent vacuum */
 					all_visible = false;
+					all_visible_or_dead = false;
 					break;
 				default:
 					elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
@@ -858,6 +865,24 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			 */
 			vacrelstats->num_dead_tuples = 0;
 			vacuumed_pages++;
+
+			/*
+			 * If the page only contains either all-visible or dead tuples, the
+			 * dead tuples themselves would have been removed by the
+			 * lazy_vacuum_page(). So we can now mark the page all-visible
+			 */
+			if (all_visible_or_dead)
+				all_visible = true;
+		}
+
+		/* 
+		 * Clear the PD_ALL_VISIBLE_OR_DEAD flag which might be left over from
+		 * the previous failed vacuum. We may set it again below
+		 */
+		if (PageIsAllVisibleOrDead(page))
+		{
+			PageClearAllVisibleOrDead(page);
+			MarkBufferDirty(buf);
 		}
 
 		freespace = PageGetHeapFreeSpace(page);
@@ -921,6 +946,23 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			MarkBufferDirty(buf);
 			visibilitymap_clear(onerel, blkno, vmbuffer);
 		}
+		/*
+		 * If the page contains only all-visible and dead tuples, remember that
+		 * information in the page header. The page will get marked all-visible
+		 * if no new actions happens between now and the second phase of
+		 * vacuum. But the visibilitymap_set() function also needs the
+		 * cutoff-xid for conflict resolution at the Hot Standby. We reuse the
+		 * pd_prune_xid field in the page header to store this cutoff-xid.
+		 *
+		 * Note: We don't override the pd_prune_xid if its already set. This is
+		 * probably not required since the page does not contain any
+		 * prunable items so the pd_prune_xid is of little use.
+		 */
+		else if (all_visible_or_dead && !PageXidIsPruneXid(page))
+		{
+			PageSetAllVisibleOrDead(page, visibility_cutoff_xid);
+			MarkBufferDirty(buf);
+		}
 
 		UnlockReleaseBuffer(buf);
 
@@ -1096,6 +1138,35 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
 		unused[uncnt++] = toff;
 	}
 
+	/*
+	 * The page is marked as PD_ALL_VISIBLE_OR_DEAD. The dead tuples we
+	 * just removed, so what remains must be all-visible. Mark the page
+	 * all-visible and also update the visibility map.
+	 */ 
+	if (PageIsAllVisibleOrDead(page))
+	{
+		Buffer vmbuffer = InvalidBuffer;
+
+		/*
+		 * We had at least one dead tuple on this page. So we must not have
+		 * marked this page as all-visible in the visibility map. But if we
+		 * had, then at least show a WARNING here
+		 */
+		if (visibilitymap_test(onerel, blkno, &vmbuffer))
+			elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
+				 RelationGetRelationName(onerel), blkno);
+		else
+			visibilitymap_set(onerel, blkno, InvalidXLogRecPtr, vmbuffer,
+					((PageHeader) (page))->pd_prune_xid); 
+
+		PageClearAllVisibleOrDead(page);
+		PageSetAllVisible(page);
+
+		if (BufferIsValid(vmbuffer))
+			ReleaseBuffer(vmbuffer);
+		vmbuffer = InvalidBuffer;
+	}
+
 	PageRepairFragmentation(page);
 
 	MarkBufferDirty(buffer);
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index fc3a69b..c2ab194 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -156,14 +156,22 @@ typedef PageHeaderData *PageHeader;
  * PD_PAGE_FULL is set if an UPDATE doesn't find enough free space in the
  * page for its new tuple version; this suggests that a prune is needed.
  * Again, this is just a hint.
+ *
+ * PD_ALL_VISIBLE_OR_DEAD is set if the first phase of VACUUM encounters a page
+ * which is all-visible except one or more dead tuples which will be removed by
+ * the second phase of VACUUM.
  */
 #define PD_HAS_FREE_LINES	0x0001		/* are there any unused line pointers? */
 #define PD_PAGE_FULL		0x0002		/* not enough free space for new
 										 * tuple? */
 #define PD_ALL_VISIBLE		0x0004		/* all tuples on page are visible to
 										 * everyone */
+#define PD_ALL_VISIBLE_OR_DEAD	0x0008	/* tuples on the page are either
+										   visible to everyone or dead for
+										   everyone */
+#define PD_XID_IS_PRUNEXID	0x0010		/* pd_prune_xid is prune xid */
 
-#define PD_VALID_FLAG_BITS	0x0007		/* OR of all valid pd_flags bits */
+#define PD_VALID_FLAG_BITS	0x001F		/* OR of all valid pd_flags bits */
 
 /*
  * Page layout version number 0 is for pre-7.3 Postgres releases.
@@ -354,9 +362,31 @@ typedef PageHeaderData *PageHeader;
 #define PageClearAllVisible(page) \
 	(((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE)
 
+#define PageXidIsPruneXid(page) \
+	(((PageHeader) (page))->pd_flags & PD_XID_IS_PRUNEXID)
+#define PageSetXidIsPruneXid(page) \
+	(((PageHeader) (page))->pd_flags |= PD_XID_IS_PRUNEXID)
+#define PageClearXidIsPruneXid(page) \
+	(((PageHeader) (page))->pd_flags &= ~PD_XID_IS_PRUNEXID)
+
+#define PageIsAllVisibleOrDead(page) \
+	(((PageHeader) (page))->pd_flags & PD_ALL_VISIBLE_OR_DEAD)
+#define PageSetAllVisibleOrDead(page, xid) \
+do { \
+	AssertMacro(!PageXidIsPruneXid(page)); \
+	(((PageHeader) (page))->pd_flags |= PD_ALL_VISIBLE_OR_DEAD); \
+	((PageHeader) (page))->pd_prune_xid = (xid); \
+} while (0)
+#define PageClearAllVisibleOrDead(page) \
+do { \
+	(((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE_OR_DEAD); \
+	((PageHeader) (page))->pd_prune_xid = InvalidTransactionId; \
+} while (0)
+
 #define PageIsPrunable(page, oldestxmin) \
 ( \
 	AssertMacro(TransactionIdIsNormal(oldestxmin)), \
+  	PageXidIsPruneXid(page) && \
 	TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) && \
 	TransactionIdPrecedes(((PageHeader) (page))->pd_prune_xid, oldestxmin) \
 )
@@ -364,11 +394,18 @@ typedef PageHeaderData *PageHeader;
 do { \
 	Assert(TransactionIdIsNormal(xid)); \
 	if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
+		!PageXidIsPruneXid(page) || \
 		TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
+	{ \
 		((PageHeader) (page))->pd_prune_xid = (xid); \
+		PageSetXidIsPruneXid(page); \
+	} \
 } while (0)
 #define PageClearPrunable(page) \
-	(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
+do { \
+	(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId); \
+	PageClearXidIsPruneXid(page); \
+} while (0)
 
 
 /* ----------------------------------------------------------------
