Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitae1525f

Browse files
committed
Fix bogus when-to-deregister-from-listener-array logic.
Since a backend adds itself to the global listener array duringExec_ListenPreCommit, it's inappropriate for it to remove itself duringExec_UnlistenCommit or Exec_UnlistenAllCommit --- that leads to failurewhen committing a transaction that did UNLISTEN then LISTEN, since we endup not registered though we should be. (This leads to missing laternotifications, or to Assert failures in assert-enabled builds.) Insteaddeal with deregistering at the bottom of AtCommit_Notify, when we know thefinal state of the listenChannels list.Also, simplify the representation of registration status by replacing thetransient backendHasExecutedInitialListen flag with an amRegisteredListenerflag.Per report from Greg Sabino Mullane. Back-patch to 9.0, where the problemwas introduced during the LISTEN/NOTIFY rewrite.
1 parent639f5ad commitae1525f

File tree

1 file changed

+22
-38
lines changed

1 file changed

+22
-38
lines changed

‎src/backend/commands/async.c

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,12 @@ static volatile sig_atomic_t notifyInterruptOccurred = 0;
349349
/* True if we've registered an on_shmem_exit cleanup */
350350
staticboolunlistenExitRegistered= false;
351351

352+
/* True if we're currently registered as a listener in asyncQueueControl */
353+
staticboolamRegisteredListener= false;
354+
352355
/* has this backend sent notifications in the current transaction? */
353356
staticboolbackendHasSentNotifications= false;
354357

355-
/* has this backend executed its first LISTEN in the current transaction? */
356-
staticboolbackendHasExecutedInitialListen= false;
357-
358358
/* GUC parameter */
359359
boolTrace_notify= false;
360360

@@ -745,6 +745,7 @@ static void
745745
Async_UnlistenOnExit(intcode,Datumarg)
746746
{
747747
Exec_UnlistenAllCommit();
748+
asyncQueueUnregister();
748749
}
749750

750751
/*
@@ -789,8 +790,6 @@ PreCommit_Notify(void)
789790
if (Trace_notify)
790791
elog(DEBUG1,"PreCommit_Notify");
791792

792-
Assert(backendHasExecutedInitialListen== false);
793-
794793
/* Preflight for any pending listen/unlisten actions */
795794
foreach(p,pendingActions)
796795
{
@@ -913,11 +912,9 @@ AtCommit_Notify(void)
913912
}
914913
}
915914

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();
921918

922919
/* And clean up */
923920
ClearPendingActionsAndNotifies();
@@ -935,19 +932,12 @@ Exec_ListenPreCommit(void)
935932
* Nothing to do if we are already listening to something, nor if we
936933
* already ran this routine in this transaction.
937934
*/
938-
if (listenChannels!=NIL||backendHasExecutedInitialListen)
935+
if (amRegisteredListener)
939936
return;
940937

941938
if (Trace_notify)
942939
elog(DEBUG1,"Exec_ListenPreCommit(%d)",MyProcPid);
943940

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-
951941
/*
952942
* Before registering, make sure we will unlisten before dying. (Note:
953943
* this action does not get undone if we abort later.)
@@ -971,6 +961,9 @@ Exec_ListenPreCommit(void)
971961
QUEUE_BACKEND_PID(MyBackendId)=MyProcPid;
972962
LWLockRelease(AsyncQueueLock);
973963

964+
/* Now we are listed in the global array, so remember we're listening */
965+
amRegisteredListener= true;
966+
974967
/*
975968
* Try to move our pointer forward as far as possible. This will skip over
976969
* already-committed notifications. Still, we could get notifications that
@@ -1043,10 +1036,6 @@ Exec_UnlistenCommit(const char *channel)
10431036
* We do not complain about unlistening something not being listened;
10441037
* should we?
10451038
*/
1046-
1047-
/* If no longer listening to anything, get out of listener array */
1048-
if (listenChannels==NIL)
1049-
asyncQueueUnregister();
10501039
}
10511040

10521041
/*
@@ -1062,8 +1051,6 @@ Exec_UnlistenAllCommit(void)
10621051

10631052
list_free_deep(listenChannels);
10641053
listenChannels=NIL;
1065-
1066-
asyncQueueUnregister();
10671054
}
10681055

10691056
/*
@@ -1181,6 +1168,9 @@ asyncQueueUnregister(void)
11811168

11821169
Assert(listenChannels==NIL);/* else caller error */
11831170

1171+
if (!amRegisteredListener)/* nothing to do */
1172+
return;
1173+
11841174
LWLockAcquire(AsyncQueueLock,LW_SHARED);
11851175
/* check if entry is valid and oldest ... */
11861176
advanceTail= (MyProcPid==QUEUE_BACKEND_PID(MyBackendId))&&
@@ -1189,6 +1179,9 @@ asyncQueueUnregister(void)
11891179
QUEUE_BACKEND_PID(MyBackendId)=InvalidPid;
11901180
LWLockRelease(AsyncQueueLock);
11911181

1182+
/* mark ourselves as no longer listed in the global array */
1183+
amRegisteredListener= false;
1184+
11921185
/* If we were the laziest backend, try to advance the tail pointer */
11931186
if (advanceTail)
11941187
asyncQueueAdvanceTail();
@@ -1545,21 +1538,12 @@ void
15451538
AtAbort_Notify(void)
15461539
{
15471540
/*
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.
15511544
*/
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();
15631547

15641548
/* And clean up */
15651549
ClearPendingActionsAndNotifies();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp