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

Commitcd89965

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 parentfdf9e21 commitcd89965

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
@@ -350,12 +350,12 @@ static volatile sig_atomic_t notifyInterruptOccurred = 0;
350350
/* True if we've registered an on_shmem_exit cleanup */
351351
staticboolunlistenExitRegistered= false;
352352

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

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

@@ -724,6 +724,7 @@ static void
724724
Async_UnlistenOnExit(intcode,Datumarg)
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
15241517
AtAbort_Notify(void)
15251518
{
15261519
/*
1527-
* If we LISTEN but then roll back the transactionwe have set our pointer
1528-
*but havenot made any entry in listenChannels. In that case, remove our
1529-
*pointer again.
1520+
* If we LISTEN but then roll back the transactionafter PreCommit_Notify,
1521+
*we haveregistered 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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp