Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Stabilize NOTIFY behavior by transmitting notifies before ReadyForQuery.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Nov 2019 19:42:59 +0000 (14:42 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Nov 2019 19:42:59 +0000 (14:42 -0500)
This patch ensures that, if any notify messages were received during
a just-finished transaction, they get sent to the frontend just before
not just after the ReadyForQuery message.  With libpq and other client
libraries that act similarly, this guarantees that the client will see
the notify messages as available as soon as it thinks the transaction
is done.

This probably makes no difference in practice, since in realistic
use-cases the application would have to cope with asynchronous
arrival of notify events anyhow.  However, it makes it a lot easier
to build cross-session-notify test cases with stable behavior.
I'm a bit surprised now that we've not seen any buildfarm instability
with the test cases added by commit b10f40bf0.  Tests that I intend
to add in an upcoming bug fix are definitely unstable without this.

Back-patch to 9.6, which is as far back as we can do NOTIFY testing
with the isolationtester infrastructure.

Discussion: https://postgr.es/m/13881.1574557302@sss.pgh.pa.us

src/backend/commands/async.c
src/backend/tcop/postgres.c

index 370c2b9a4fba33da612169eb20132465e8e3646c..50867756461e69957e45171c9e5de404cd80b3fc 100644 (file)
@@ -1885,11 +1885,13 @@ HandleNotifyInterrupt(void)
 /*
  * ProcessNotifyInterrupt
  *
- *     This is called just after waiting for a frontend command.  If a
- *     interrupt arrives (via HandleNotifyInterrupt()) while reading, the
- *     read will be interrupted via the process's latch, and this routine
- *     will get called.  If we are truly idle (ie, *not* inside a transaction
- *     block), process the incoming notifies.
+ *     This is called if we see notifyInterruptPending set, just before
+ *     transmitting ReadyForQuery at the end of a frontend command, and
+ *     also if a notify signal occurs while reading from the frontend.
+ *     HandleNotifyInterrupt() will cause the read to be interrupted
+ *     via the process's latch, and this routine will get called.
+ *     If we are truly idle (ie, *not* inside a transaction block),
+ *     process the incoming notifies.
  */
 void
 ProcessNotifyInterrupt(void)
index d7a72c0766ba175d5db4c4482006b97fba5ac204..3b85e48333d9a1f03f79be52bcb142b3fe3cea90 100644 (file)
@@ -4194,7 +4194,18 @@ PostgresMain(int argc, char *argv[],
            }
            else
            {
+               /* Send out notify signals and transmit self-notifies */
                ProcessCompletedNotifies();
+
+               /*
+                * Also process incoming notifies, if any.  This is mostly to
+                * ensure stable behavior in tests: if any notifies were
+                * received during the just-finished transaction, they'll be
+                * seen by the client before ReadyForQuery is.
+                */
+               if (notifyInterruptPending)
+                   ProcessNotifyInterrupt();
+
                pgstat_report_stat(false);
 
                set_ps_display("idle", false);