/* True if we've registered an on_shmem_exit cleanup */
static bool unlistenExitRegistered = false;
+/* True if we're currently registered as a listener in asyncQueueControl */
+static bool amRegisteredListener = false;
+
/* has this backend sent notifications in the current transaction? */
static bool backendHasSentNotifications = false;
-/* has this backend executed its first LISTEN in the current transaction? */
-static bool backendHasExecutedInitialListen = false;
-
/* GUC parameter */
bool Trace_notify = false;
Async_UnlistenOnExit(int code, Datum arg)
{
Exec_UnlistenAllCommit();
+ asyncQueueUnregister();
}
/*
if (Trace_notify)
elog(DEBUG1, "PreCommit_Notify");
- Assert(backendHasExecutedInitialListen == false);
-
/* Preflight for any pending listen/unlisten actions */
foreach(p, pendingActions)
{
}
}
- /*
- * If we did an initial LISTEN, listenChannels now has the entry, so we no
- * longer need or want the flag to be set.
- */
- backendHasExecutedInitialListen = false;
+ /* If no longer listening to anything, get out of listener array */
+ if (amRegisteredListener && listenChannels == NIL)
+ asyncQueueUnregister();
/* And clean up */
ClearPendingActionsAndNotifies();
* Nothing to do if we are already listening to something, nor if we
* already ran this routine in this transaction.
*/
- if (listenChannels != NIL || backendHasExecutedInitialListen)
+ if (amRegisteredListener)
return;
if (Trace_notify)
elog(DEBUG1, "Exec_ListenPreCommit(%d)", MyProcPid);
- /*
- * We need this variable to detect an aborted initial LISTEN. In that case
- * we would set up our pointer but not listen on any channel. This flag
- * gets cleared in AtCommit_Notify or AtAbort_Notify().
- */
- backendHasExecutedInitialListen = true;
-
/*
* Before registering, make sure we will unlisten before dying. (Note:
* this action does not get undone if we abort later.)
QUEUE_BACKEND_PID(MyBackendId) = MyProcPid;
LWLockRelease(AsyncQueueLock);
+ /* Now we are listed in the global array, so remember we're listening */
+ amRegisteredListener = true;
+
/*
* Try to move our pointer forward as far as possible. This will skip over
* already-committed notifications. Still, we could get notifications that
* We do not complain about unlistening something not being listened;
* should we?
*/
-
- /* If no longer listening to anything, get out of listener array */
- if (listenChannels == NIL)
- asyncQueueUnregister();
}
/*
list_free_deep(listenChannels);
listenChannels = NIL;
-
- asyncQueueUnregister();
}
/*
Assert(listenChannels == NIL); /* else caller error */
+ if (!amRegisteredListener) /* nothing to do */
+ return;
+
LWLockAcquire(AsyncQueueLock, LW_SHARED);
/* check if entry is valid and oldest ... */
advanceTail = (MyProcPid == QUEUE_BACKEND_PID(MyBackendId)) &&
QUEUE_BACKEND_PID(MyBackendId) = InvalidPid;
LWLockRelease(AsyncQueueLock);
+ /* mark ourselves as no longer listed in the global array */
+ amRegisteredListener = false;
+
/* If we were the laziest backend, try to advance the tail pointer */
if (advanceTail)
asyncQueueAdvanceTail();
AtAbort_Notify(void)
{
/*
- * If we LISTEN but then roll back the transaction we have set our pointer
- * but have not made any entry in listenChannels. In that case, remove our
- * pointer again.
+ * If we LISTEN but then roll back the transaction after PreCommit_Notify,
+ * we have registered as a listener but have not made any entry in
+ * listenChannels. In that case, deregister again.
*/
- if (backendHasExecutedInitialListen)
- {
- /*
- * Checking listenChannels should be redundant but it can't hurt doing
- * it for safety reasons.
- */
- if (listenChannels == NIL)
- asyncQueueUnregister();
-
- backendHasExecutedInitialListen = false;
- }
+ if (amRegisteredListener && listenChannels == NIL)
+ asyncQueueUnregister();
/* And clean up */
ClearPendingActionsAndNotifies();