From 0b928fb91b5b3aa527372495e9fa4778c5b5bfab Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig@2ndquadrant.com>
Date: Thu, 25 Aug 2016 10:59:57 +0800
Subject: [PATCH 1/4] Release SLRU control lock before reporting I/O error

To allow callers to trap SLRU I/O errors with a PG_TRY() / PG_CATCH() block,
slru.c functions that acquire the SLRU control lock now also release the SLRU
control LWLock before reporting I/O errors.

Many SLRU functions previously took the LWLock and threw exceptions with it
still held.
---
 src/backend/access/transam/slru.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index bbae584..f020522 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -366,7 +366,8 @@ SimpleLruWaitIO(SlruCtl ctl, int slotno)
  * Return value is the shared-buffer slot number now holding the page.
  * The buffer's LRU access info is updated.
  *
- * Control lock must be held at entry, and will be held at exit.
+ * Control lock must be held at entry, and will be held at normal exit.
+ * The control lock is released if an exception is thrown.
  */
 int
 SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
@@ -439,7 +440,10 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 
 		/* Now it's okay to ereport if we failed */
 		if (!ok)
+		{
+			LWLockRelease(shared->ControlLock);
 			SlruReportIOError(ctl, pageno, xid);
+		}
 
 		SlruRecentlyUsed(shared, slotno);
 		return slotno;
@@ -457,8 +461,9 @@ SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
  * Return value is the shared-buffer slot number now holding the page.
  * The buffer's LRU access info is updated.
  *
- * Control lock must NOT be held at entry, but will be held at exit.
- * It is unspecified whether the lock will be shared or exclusive.
+ * Control lock must NOT be held at entry, but will be held at exit
+ * unless an exception is thrown. It is unspecified whether the lock
+ * will be shared or exclusive.
  */
 int
 SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
@@ -498,7 +503,8 @@ SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
  * the write).  However, we *do* attempt a fresh write even if the page
  * is already being written; this is for checkpoints.
  *
- * Control lock must be held at entry, and will be held at exit.
+ * Control lock must be held at entry, and will be held at normal exit.
+ * The lock is released if an exception is thrown.
  */
 static void
 SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
@@ -564,7 +570,10 @@ SlruInternalWritePage(SlruCtl ctl, int slotno, SlruFlush fdata)
 
 	/* Now it's okay to ereport if we failed */
 	if (!ok)
+	{
+		LWLockRelease(shared->ControlLock);
 		SlruReportIOError(ctl, pageno, InvalidTransactionId);
+	}
 }
 
 /*
-- 
2.5.5

