0001-Stamp-deleted-GIN-page-with-xid-to-prevent-early-reu.patch

application/octet-stream

Filename: 0001-Stamp-deleted-GIN-page-with-xid-to-prevent-early-reu.patch
Type: application/octet-stream
Part: 0
Message: Re: Connections hang indefinitely while taking a gin index's LWLock buffer_content lock

Patch

Format: format-patch
Series: patch 0001
Subject: Stamp deleted GIN page with xid to prevent early reuse
File+
src/backend/access/gin/ginutil.c 6 1
src/backend/access/gin/ginxlog.c 1 0
src/include/access/gin_private.h 3 0
src/include/access/ginxlog.h 1 0
From 389ccf54b12cf32d49222e7c2b5b6b89083b98c7 Mon Sep 17 00:00:00 2001
From: Andrey <amborodin@acm.org>
Date: Mon, 10 Dec 2018 18:49:47 +0500
Subject: [PATCH] Stamp deleted GIN page with xid to prevent early reuse

---
 src/backend/access/gin/ginutil.c | 7 ++++++-
 src/backend/access/gin/ginxlog.c | 1 +
 src/include/access/gin_private.h | 3 +++
 src/include/access/ginxlog.h     | 1 +
 4 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index d7696a1ad0..9072ee6260 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -314,7 +314,12 @@ GinNewBuffer(Relation index)
 			if (PageIsNew(page))
 				return buffer;	/* OK to use, if never initialized */
 
-			if (GinPageIsDeleted(page))
+			/*
+			 * We should not reuse page until every transaction started before
+			 * deletion is over
+			 */
+			if (GinPageIsDeleted(page)
+				&& TransactionIdPrecedes(GinPageGetDeleteXid(page), RecentGlobalDataXmin))
 				return buffer;	/* OK to use */
 
 			LockBuffer(buffer, GIN_UNLOCK);
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 7701a2d6bf..7821f69077 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -518,6 +518,7 @@ ginRedoDeletePage(XLogReaderState *record)
 		page = BufferGetPage(dbuffer);
 		Assert(GinPageIsData(page));
 		GinPageGetOpaque(page)->flags = GIN_DELETED;
+		GinPageSetDeleteXid(page, data->deleteXid);
 		PageSetLSN(page, lsn);
 		MarkBufferDirty(dbuffer);
 	}
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index 81bf8734ce..83d2621488 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -44,6 +44,9 @@ typedef struct GinOptions
 #define GIN_SHARE	BUFFER_LOCK_SHARE
 #define GIN_EXCLUSIVE  BUFFER_LOCK_EXCLUSIVE
 
+#define GinPageGetDeleteXid(page) ( ((PageHeader) (page))->pd_prune_xid )
+#define GinPageSetDeleteXid(page, val) ( ((PageHeader) (page))->pd_prune_xid = val)
+
 
 /*
  * GinState: working data structure describing the index being worked on
diff --git a/src/include/access/ginxlog.h b/src/include/access/ginxlog.h
index 64a3c9e18b..d7f44d6b83 100644
--- a/src/include/access/ginxlog.h
+++ b/src/include/access/ginxlog.h
@@ -158,6 +158,7 @@ typedef struct ginxlogDeletePage
 {
 	OffsetNumber parentOffset;
 	BlockNumber rightLink;
+	TransactionId deleteXid; /* last Xid which could see page in scan */
 } ginxlogDeletePage;
 
 #define XLOG_GIN_UPDATE_META_PAGE 0x60
-- 
2.17.2 (Apple Git-113)