From c0db16ec3bb971fb41b9e7f568b5cb168aa462ba Mon Sep 17 00:00:00 2001
From: Martijn van Oosterhout <oosterhout@fox-it.com>
Date: Mon, 3 Jun 2019 17:13:31 +0200
Subject: [PATCH 1/3] Only try advancing tail pointer when it's useful.

Advancing the tail pointer requires an exclusive lock which can block
backends from other databases, so it's worth keeping these attempts to a
minimum.
---
 src/backend/commands/async.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 738e6ec7e2..53e28fe777 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -89,11 +89,9 @@
  *	  Inbound-notify processing consists of reading all of the notifications
  *	  that have arrived since scanning last time. We read every notification
  *	  until we reach either a notification from an uncommitted transaction or
- *	  the head pointer's position. Then we check if we were the laziest
- *	  backend: if our pointer is set to the same position as the global tail
- *	  pointer is set, then we move the global tail pointer ahead to where the
- *	  second-laziest backend is (in general, we take the MIN of the current
- *	  head position and all active backends' new tail pointers). Whenever we
+ *	  the head pointer's position. Then we check if we can advance the global
+ *	  tail pointer to a new page, if so we take the MIN of the current
+ *	  head position and all active backends' new tail pointers. Whenever we
  *	  move the global tail pointer we also truncate now-unused pages (i.e.,
  *	  delete files in pg_notify/ that are no longer used).
  *
@@ -1749,7 +1747,6 @@ asyncQueueReadAllNotifications(void)
 	QueuePosition oldpos;
 	QueuePosition head;
 	Snapshot	snapshot;
-	bool		advanceTail;
 
 	/* page_buffer must be adequately aligned, so use a union */
 	union
@@ -1871,12 +1868,10 @@ asyncQueueReadAllNotifications(void)
 		/* Update shared state */
 		LWLockAcquire(AsyncQueueLock, LW_SHARED);
 		QUEUE_BACKEND_POS(MyBackendId) = pos;
-		advanceTail = QUEUE_POS_EQUAL(oldpos, QUEUE_TAIL);
 		LWLockRelease(AsyncQueueLock);
 
-		/* If we were the laziest backend, try to advance the tail pointer */
-		if (advanceTail)
-			asyncQueueAdvanceTail();
+		/* Check if tail can be advanced */
+		asyncQueueAdvanceTail();
 
 		PG_RE_THROW();
 	}
@@ -1885,12 +1880,10 @@ asyncQueueReadAllNotifications(void)
 	/* Update shared state */
 	LWLockAcquire(AsyncQueueLock, LW_SHARED);
 	QUEUE_BACKEND_POS(MyBackendId) = pos;
-	advanceTail = QUEUE_POS_EQUAL(oldpos, QUEUE_TAIL);
 	LWLockRelease(AsyncQueueLock);
 
-	/* If we were the laziest backend, try to advance the tail pointer */
-	if (advanceTail)
-		asyncQueueAdvanceTail();
+	/* Check if tail can be advanced */
+	asyncQueueAdvanceTail();
 
 	/* Done with snapshot */
 	UnregisterSnapshot(snapshot);
@@ -2010,6 +2003,14 @@ asyncQueueAdvanceTail(void)
 	int			newtailpage;
 	int			boundary;
 
+	/*
+	 * Advancing the tail is expensive (it takes an exclusive lock which
+	 * can block committing backends) so don't bother if we can't advance
+	 * at least a page.
+	 */
+	if (QUEUE_POS_PAGE(QUEUE_TAIL) == QUEUE_POS_PAGE(QUEUE_HEAD))
+		return;
+
 	LWLockAcquire(AsyncQueueLock, LW_EXCLUSIVE);
 	min = QUEUE_HEAD;
 	for (i = 1; i <= MaxBackends; i++)
-- 
2.11.0

