From 085a3d52d743703db2034674e9571161e852a594 Mon Sep 17 00:00:00 2001
From: ashu <ashu@localhost.localdomain>
Date: Fri, 17 Mar 2017 11:37:16 +0530
Subject: [PATCH] Reset LH_PAGE_HAS_DEAD_TUPLES flag during replay v3

Patch by Ashutosh Sharma
---
 src/backend/access/hash/hash.c       |  8 +++++++-
 src/backend/access/hash/hash_xlog.c  | 21 +++++++++++++++++++++
 src/backend/access/hash/hashinsert.c |  8 ++++++++
 src/include/access/hash_xlog.h       |  2 ++
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index cfcec34..869ddce 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -790,6 +790,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 		OffsetNumber deletable[MaxOffsetNumber];
 		int			ndeletable = 0;
 		bool		retain_pin = false;
+		bool		clear_dead_marking = false;
 
 		vacuum_delay_point();
 
@@ -877,11 +878,15 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 			/*
 			 * Let us mark the page as clean if vacuum removes the DEAD tuples
 			 * from an index page. We do this by clearing LH_PAGE_HAS_DEAD_TUPLES
-			 * flag. Clearing this flag is just a hint; replay won't redo this.
+			 * flag. Clearing this flag is just a hint; replay will check the
+			 * status of clear_dead_marking flag before redo it.
 			 */
 			if (tuples_removed && *tuples_removed > 0 &&
 				opaque->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES)
+			{
 				opaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
+				clear_dead_marking = true;
+			}
 
 			MarkBufferDirty(buf);
 
@@ -891,6 +896,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 				xl_hash_delete xlrec;
 				XLogRecPtr	recptr;
 
+				xlrec.clear_dead_marking = clear_dead_marking;
 				xlrec.is_primary_bucket_page = (buf == bucket_buf) ? true : false;
 
 				XLogBeginInsert();
diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 8647e8c..ac82092 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -859,6 +859,19 @@ hash_xlog_delete(XLogReaderState *record)
 				PageIndexMultiDelete(page, unused, unend - unused);
 		}
 
+		/*
+		 * Mark the page as not containing any LP_DEAD items only if
+		 * clear_dead_marking flag is set to true. See comments in
+		 * hashbucketcleanup() for details.
+		 */
+		if (xldata->clear_dead_marking)
+		{
+			HashPageOpaque pageopaque;
+
+			pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+			pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
+		}
+
 		PageSetLSN(page, lsn);
 		MarkBufferDirty(deletebuf);
 	}
@@ -1078,6 +1091,7 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
 	Buffer metabuf;
 	Page page;
 	XLogRedoAction action;
+	HashPageOpaque pageopaque;
 
 	xldata = (xl_hash_vacuum_one_page *) XLogRecGetData(record);
 
@@ -1126,6 +1140,13 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
 				PageIndexMultiDelete(page, unused, unend - unused);
 		}
 
+		/*
+		 * Mark the page as not containing any LP_DEAD items. See comments
+		 * in _hash_vacuum_one_page() for details.
+		 */
+		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
+
 		PageSetLSN(page, lsn);
 		MarkBufferDirty(buffer);
 	}
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index 8b6d0a0..8640e85 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -374,6 +374,14 @@ _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
 
 		PageIndexMultiDelete(page, deletable, ndeletable);
 
+		/*
+		 * Mark the page as not containing any LP_DEAD items. This is not
+		 * certainly true (there might be some that have recently been marked,
+		 * but weren't included in our target-item list), but it will almost
+		 * always be true and it doesn't seem worth an additional page scan
+		 * to check it. Remember that LH_PAGE_HAS_DEAD_TUPLES is only a hint
+		 * anyway.
+		 */
 		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
 		pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 
diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h
index dfd9237..4db40b4 100644
--- a/src/include/access/hash_xlog.h
+++ b/src/include/access/hash_xlog.h
@@ -197,6 +197,8 @@ typedef struct xl_hash_squeeze_page
  */
 typedef struct xl_hash_delete
 {
+	bool		clear_dead_marking;		/* TRUE if VACUUM clears
+										 * LH_PAGE_HAS_DEAD_TUPLES flag */
 	bool		is_primary_bucket_page; /* TRUE if the operation is for
 										 * primary bucket page */
 }	xl_hash_delete;
-- 
1.8.3.1

