From 17c241a2e307e70465c235248c17ac70d34fd175 Mon Sep 17 00:00:00 2001 From: Martijn van Oosterhout Date: Mon, 3 Jun 2019 17:13:31 +0200 Subject: [PATCH 1/2] 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..c1b0705234 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