Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0d11fed

Browse files
committed
Avoid transaction-commit race condition while receiving a NOTIFY message.
Use TransactionIdIsInProgress, then TransactionIdDidCommit, to distinguish whether a NOTIFY message's originating transaction is in progress, committed, or aborted. The previous coding could accept a message from a transaction that was still in-progress according to the PGPROC array; if the client were fast enough at starting a new transaction, it might fail to see table rows added/updated by the message-sending transaction. Which of course would usually be the point of receiving the message. We noted this type of race condition long ago in tqual.c, but async.c overlooked it. The race condition probably cannot occur unless there are multiple NOTIFY senders in action, since an individual backend doesn't send NOTIFY signals until well after it's done committing. But if two senders commit in close succession, it's certainly possible that we could see the second sender's message within the race condition window while responding to the signal from the first one. Per bug #9557 from Marko Tiikkaja. This patch is slightly more invasive than what he proposed, since it removes the now-redundant TransactionIdDidAbort call. Back-patch to 9.0, where the current NOTIFY implementation was introduced.
1 parent 4738cc3 commit 0d11fed

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

src/backend/commands/async.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
#include "miscadmin.h"
127127
#include "storage/ipc.h"
128128
#include "storage/lmgr.h"
129+
#include "storage/procarray.h"
129130
#include "storage/procsignal.h"
130131
#include "storage/sinval.h"
131132
#include "tcop/tcopprot.h"
@@ -1980,7 +1981,27 @@ asyncQueueProcessPageEntries(QueuePosition *current,
19801981
/* Ignore messages destined for other databases */
19811982
if (qe->dboid == MyDatabaseId)
19821983
{
1983-
if (TransactionIdDidCommit(qe->xid))
1984+
if (TransactionIdIsInProgress(qe->xid))
1985+
{
1986+
/*
1987+
* The source transaction is still in progress, so we can't
1988+
* process this message yet. Break out of the loop, but first
1989+
* back up *current so we will reprocess the message next
1990+
* time. (Note: it is unlikely but not impossible for
1991+
* TransactionIdDidCommit to fail, so we can't really avoid
1992+
* this advance-then-back-up behavior when dealing with an
1993+
* uncommitted message.)
1994+
*
1995+
* Note that we must test TransactionIdIsInProgress before we
1996+
* test TransactionIdDidCommit, else we might return a message
1997+
* from a transaction that is not yet visible to snapshots;
1998+
* compare the comments at the head of tqual.c.
1999+
*/
2000+
*current = thisentry;
2001+
reachedStop = true;
2002+
break;
2003+
}
2004+
else if (TransactionIdDidCommit(qe->xid))
19842005
{
19852006
/* qe->data is the null-terminated channel name */
19862007
char *channel = qe->data;
@@ -1993,27 +2014,12 @@ asyncQueueProcessPageEntries(QueuePosition *current,
19932014
NotifyMyFrontEnd(channel, payload, qe->srcPid);
19942015
}
19952016
}
1996-
else if (TransactionIdDidAbort(qe->xid))
1997-
{
1998-
/*
1999-
* If the source transaction aborted, we just ignore its
2000-
* notifications.
2001-
*/
2002-
}
20032017
else
20042018
{
20052019
/*
2006-
* The transaction has neither committed nor aborted so far,
2007-
* so we can't process its message yet. Break out of the
2008-
* loop, but first back up *current so we will reprocess the
2009-
* message next time. (Note: it is unlikely but not
2010-
* impossible for TransactionIdDidCommit to fail, so we can't
2011-
* really avoid this advance-then-back-up behavior when
2012-
* dealing with an uncommitted message.)
2020+
* The source transaction aborted or crashed, so we just
2021+
* ignore its notifications.
20132022
*/
2014-
*current = thisentry;
2015-
reachedStop = true;
2016-
break;
20172023
}
20182024
}
20192025

0 commit comments

Comments
 (0)