@@ -350,12 +350,12 @@ static volatile sig_atomic_t notifyInterruptOccurred = 0;
350350/* True if we've registered an on_shmem_exit cleanup */
351351static bool unlistenExitRegistered = false;
352352
353+ /* True if we're currently registered as a listener in asyncQueueControl */
354+ static bool amRegisteredListener = false;
355+
353356/* has this backend sent notifications in the current transaction? */
354357static bool backendHasSentNotifications = false;
355358
356- /* has this backend executed its first LISTEN in the current transaction? */
357- static bool backendHasExecutedInitialListen = false;
358-
359359/* GUC parameter */
360360bool Trace_notify = false;
361361
@@ -724,6 +724,7 @@ static void
724724Async_UnlistenOnExit (int code , Datum arg )
725725{
726726 Exec_UnlistenAllCommit ();
727+ asyncQueueUnregister ();
727728}
728729
729730/*
@@ -768,8 +769,6 @@ PreCommit_Notify(void)
768769 if (Trace_notify )
769770 elog (DEBUG1 , "PreCommit_Notify" );
770771
771- Assert (backendHasExecutedInitialListen == false);
772-
773772 /* Preflight for any pending listen/unlisten actions */
774773 foreach (p , pendingActions )
775774 {
@@ -892,11 +891,9 @@ AtCommit_Notify(void)
892891 }
893892 }
894893
895- /*
896- * If we did an initial LISTEN, listenChannels now has the entry, so we no
897- * longer need or want the flag to be set.
898- */
899- backendHasExecutedInitialListen = false;
894+ /* If no longer listening to anything, get out of listener array */
895+ if (amRegisteredListener && listenChannels == NIL )
896+ asyncQueueUnregister ();
900897
901898 /* And clean up */
902899 ClearPendingActionsAndNotifies ();
@@ -914,19 +911,12 @@ Exec_ListenPreCommit(void)
914911 * Nothing to do if we are already listening to something, nor if we
915912 * already ran this routine in this transaction.
916913 */
917- if (listenChannels != NIL || backendHasExecutedInitialListen )
914+ if (amRegisteredListener )
918915 return ;
919916
920917 if (Trace_notify )
921918 elog (DEBUG1 , "Exec_ListenPreCommit(%d)" , MyProcPid );
922919
923- /*
924- * We need this variable to detect an aborted initial LISTEN. In that case
925- * we would set up our pointer but not listen on any channel. This flag
926- * gets cleared in AtCommit_Notify or AtAbort_Notify().
927- */
928- backendHasExecutedInitialListen = true;
929-
930920 /*
931921 * Before registering, make sure we will unlisten before dying. (Note:
932922 * this action does not get undone if we abort later.)
@@ -950,6 +940,9 @@ Exec_ListenPreCommit(void)
950940 QUEUE_BACKEND_PID (MyBackendId ) = MyProcPid ;
951941 LWLockRelease (AsyncQueueLock );
952942
943+ /* Now we are listed in the global array, so remember we're listening */
944+ amRegisteredListener = true;
945+
953946 /*
954947 * Try to move our pointer forward as far as possible. This will skip over
955948 * already-committed notifications. Still, we could get notifications that
@@ -1022,10 +1015,6 @@ Exec_UnlistenCommit(const char *channel)
10221015 * We do not complain about unlistening something not being listened;
10231016 * should we?
10241017 */
1025-
1026- /* If no longer listening to anything, get out of listener array */
1027- if (listenChannels == NIL )
1028- asyncQueueUnregister ();
10291018}
10301019
10311020/*
@@ -1041,8 +1030,6 @@ Exec_UnlistenAllCommit(void)
10411030
10421031 list_free_deep (listenChannels );
10431032 listenChannels = NIL ;
1044-
1045- asyncQueueUnregister ();
10461033}
10471034
10481035/*
@@ -1160,6 +1147,9 @@ asyncQueueUnregister(void)
11601147
11611148 Assert (listenChannels == NIL ); /* else caller error */
11621149
1150+ if (!amRegisteredListener ) /* nothing to do */
1151+ return ;
1152+
11631153 LWLockAcquire (AsyncQueueLock , LW_SHARED );
11641154 /* check if entry is valid and oldest ... */
11651155 advanceTail = (MyProcPid == QUEUE_BACKEND_PID (MyBackendId )) &&
@@ -1168,6 +1158,9 @@ asyncQueueUnregister(void)
11681158 QUEUE_BACKEND_PID (MyBackendId ) = InvalidPid ;
11691159 LWLockRelease (AsyncQueueLock );
11701160
1161+ /* mark ourselves as no longer listed in the global array */
1162+ amRegisteredListener = false;
1163+
11711164 /* If we were the laziest backend, try to advance the tail pointer */
11721165 if (advanceTail )
11731166 asyncQueueAdvanceTail ();
@@ -1524,21 +1517,12 @@ void
15241517AtAbort_Notify (void )
15251518{
15261519 /*
1527- * If we LISTEN but then roll back the transaction we have set our pointer
1528- * but have not made any entry in listenChannels. In that case, remove our
1529- * pointer again.
1520+ * If we LISTEN but then roll back the transaction after PreCommit_Notify,
1521+ * we have registered as a listener but have not made any entry in
1522+ * listenChannels. In that case, deregister again.
15301523 */
1531- if (backendHasExecutedInitialListen )
1532- {
1533- /*
1534- * Checking listenChannels should be redundant but it can't hurt doing
1535- * it for safety reasons.
1536- */
1537- if (listenChannels == NIL )
1538- asyncQueueUnregister ();
1539-
1540- backendHasExecutedInitialListen = false;
1541- }
1524+ if (amRegisteredListener && listenChannels == NIL )
1525+ asyncQueueUnregister ();
15421526
15431527 /* And clean up */
15441528 ClearPendingActionsAndNotifies ();
0 commit comments