@@ -349,12 +349,12 @@ static volatile sig_atomic_t notifyInterruptOccurred = 0;
349
349
/* True if we've registered an on_shmem_exit cleanup */
350
350
static bool unlistenExitRegistered = false;
351
351
352
+ /* True if we're currently registered as a listener in asyncQueueControl */
353
+ static bool amRegisteredListener = false;
354
+
352
355
/* has this backend sent notifications in the current transaction? */
353
356
static bool backendHasSentNotifications = false;
354
357
355
- /* has this backend executed its first LISTEN in the current transaction? */
356
- static bool backendHasExecutedInitialListen = false;
357
-
358
358
/* GUC parameter */
359
359
bool Trace_notify = false;
360
360
@@ -745,6 +745,7 @@ static void
745
745
Async_UnlistenOnExit (int code ,Datum arg )
746
746
{
747
747
Exec_UnlistenAllCommit ();
748
+ asyncQueueUnregister ();
748
749
}
749
750
750
751
/*
@@ -789,8 +790,6 @@ PreCommit_Notify(void)
789
790
if (Trace_notify )
790
791
elog (DEBUG1 ,"PreCommit_Notify" );
791
792
792
- Assert (backendHasExecutedInitialListen == false);
793
-
794
793
/* Preflight for any pending listen/unlisten actions */
795
794
foreach (p ,pendingActions )
796
795
{
@@ -913,11 +912,9 @@ AtCommit_Notify(void)
913
912
}
914
913
}
915
914
916
- /*
917
- * If we did an initial LISTEN, listenChannels now has the entry, so we no
918
- * longer need or want the flag to be set.
919
- */
920
- backendHasExecutedInitialListen = false;
915
+ /* If no longer listening to anything, get out of listener array */
916
+ if (amRegisteredListener && listenChannels == NIL )
917
+ asyncQueueUnregister ();
921
918
922
919
/* And clean up */
923
920
ClearPendingActionsAndNotifies ();
@@ -935,19 +932,12 @@ Exec_ListenPreCommit(void)
935
932
* Nothing to do if we are already listening to something, nor if we
936
933
* already ran this routine in this transaction.
937
934
*/
938
- if (listenChannels != NIL || backendHasExecutedInitialListen )
935
+ if (amRegisteredListener )
939
936
return ;
940
937
941
938
if (Trace_notify )
942
939
elog (DEBUG1 ,"Exec_ListenPreCommit(%d)" ,MyProcPid );
943
940
944
- /*
945
- * We need this variable to detect an aborted initial LISTEN. In that case
946
- * we would set up our pointer but not listen on any channel. This flag
947
- * gets cleared in AtCommit_Notify or AtAbort_Notify().
948
- */
949
- backendHasExecutedInitialListen = true;
950
-
951
941
/*
952
942
* Before registering, make sure we will unlisten before dying. (Note:
953
943
* this action does not get undone if we abort later.)
@@ -971,6 +961,9 @@ Exec_ListenPreCommit(void)
971
961
QUEUE_BACKEND_PID (MyBackendId )= MyProcPid ;
972
962
LWLockRelease (AsyncQueueLock );
973
963
964
+ /* Now we are listed in the global array, so remember we're listening */
965
+ amRegisteredListener = true;
966
+
974
967
/*
975
968
* Try to move our pointer forward as far as possible. This will skip over
976
969
* already-committed notifications. Still, we could get notifications that
@@ -1043,10 +1036,6 @@ Exec_UnlistenCommit(const char *channel)
1043
1036
* We do not complain about unlistening something not being listened;
1044
1037
* should we?
1045
1038
*/
1046
-
1047
- /* If no longer listening to anything, get out of listener array */
1048
- if (listenChannels == NIL )
1049
- asyncQueueUnregister ();
1050
1039
}
1051
1040
1052
1041
/*
@@ -1062,8 +1051,6 @@ Exec_UnlistenAllCommit(void)
1062
1051
1063
1052
list_free_deep (listenChannels );
1064
1053
listenChannels = NIL ;
1065
-
1066
- asyncQueueUnregister ();
1067
1054
}
1068
1055
1069
1056
/*
@@ -1181,6 +1168,9 @@ asyncQueueUnregister(void)
1181
1168
1182
1169
Assert (listenChannels == NIL );/* else caller error */
1183
1170
1171
+ if (!amRegisteredListener )/* nothing to do */
1172
+ return ;
1173
+
1184
1174
LWLockAcquire (AsyncQueueLock ,LW_SHARED );
1185
1175
/* check if entry is valid and oldest ... */
1186
1176
advanceTail = (MyProcPid == QUEUE_BACKEND_PID (MyBackendId ))&&
@@ -1189,6 +1179,9 @@ asyncQueueUnregister(void)
1189
1179
QUEUE_BACKEND_PID (MyBackendId )= InvalidPid ;
1190
1180
LWLockRelease (AsyncQueueLock );
1191
1181
1182
+ /* mark ourselves as no longer listed in the global array */
1183
+ amRegisteredListener = false;
1184
+
1192
1185
/* If we were the laziest backend, try to advance the tail pointer */
1193
1186
if (advanceTail )
1194
1187
asyncQueueAdvanceTail ();
@@ -1545,21 +1538,12 @@ void
1545
1538
AtAbort_Notify (void )
1546
1539
{
1547
1540
/*
1548
- * If we LISTEN but then roll back the transactionwe have set our pointer
1549
- *but havenot made any entry in listenChannels. In that case, remove our
1550
- *pointer again.
1541
+ * If we LISTEN but then roll back the transactionafter PreCommit_Notify,
1542
+ *we haveregistered as a listener but have not made any entry in
1543
+ *listenChannels. In that case, deregister again.
1551
1544
*/
1552
- if (backendHasExecutedInitialListen )
1553
- {
1554
- /*
1555
- * Checking listenChannels should be redundant but it can't hurt doing
1556
- * it for safety reasons.
1557
- */
1558
- if (listenChannels == NIL )
1559
- asyncQueueUnregister ();
1560
-
1561
- backendHasExecutedInitialListen = false;
1562
- }
1545
+ if (amRegisteredListener && listenChannels == NIL )
1546
+ asyncQueueUnregister ();
1563
1547
1564
1548
/* And clean up */
1565
1549
ClearPendingActionsAndNotifies ();