Cancel running query if it is detected that the connection to the client is
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 9 Dec 2011 09:37:21 +0000 (11:37 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 9 Dec 2011 12:21:36 +0000 (14:21 +0200)
lost. The only way we detect that at the moment is when write() fails when
we try to write to the socket.

Florian Pflug with small changes by me, reviewed by Greg Jaskiewicz.

src/backend/libpq/pqcomm.c
src/backend/tcop/postgres.c
src/backend/utils/init/globals.c
src/include/miscadmin.h

index b83a2efb6989383552166bd6ddfa95ae046f809d..c36cf318267175def34699cefc899143c5207632 100644 (file)
@@ -1247,9 +1247,13 @@ internal_flush(void)
 
            /*
             * We drop the buffered data anyway so that processing can
-            * continue, even though we'll probably quit soon.
+            * continue, even though we'll probably quit soon. We also
+            * set a flag that'll cause the next CHECK_FOR_INTERRUPTS
+            * to terminate the connection.
             */
            PqSendStart = PqSendPointer = 0;
+           ClientConnectionLost = 1;
+           InterruptPending = 1;
            return EOF;
        }
 
index 976a832135ea63d6048e6171b97024a68419dc43..5bb16e010cc9975e16409c4356894d95fa251f8f 100644 (file)
@@ -2823,6 +2823,18 @@ ProcessInterrupts(void)
                    (errcode(ERRCODE_ADMIN_SHUTDOWN),
             errmsg("terminating connection due to administrator command")));
    }
+   if (ClientConnectionLost)
+   {
+       QueryCancelPending = false;     /* lost connection trumps QueryCancel */
+       ImmediateInterruptOK = false;   /* not idle anymore */
+       DisableNotifyInterrupt();
+       DisableCatchupInterrupt();
+       /* don't send to client, we already know the connection to be dead. */
+       whereToSendOutput = DestNone;
+       ereport(FATAL,
+               (errcode(ERRCODE_CONNECTION_FAILURE),
+                errmsg("connection to client lost")));
+   }
    if (QueryCancelPending)
    {
        QueryCancelPending = false;
index 9ce64e67629bc7c9c776b141566a9700c97f11e6..9417c7a3b04955c2221addae6e8a94d092d5cf9a 100644 (file)
@@ -29,6 +29,7 @@ ProtocolVersion FrontendProtocol;
 volatile bool InterruptPending = false;
 volatile bool QueryCancelPending = false;
 volatile bool ProcDiePending = false;
+volatile bool ClientConnectionLost = false;
 volatile bool ImmediateInterruptOK = false;
 volatile uint32 InterruptHoldoffCount = 0;
 volatile uint32 CritSectionCount = 0;
index 4ee08fead6fea61c0fde3a7710d807ea16831d40..1df7723d9957a45ee6049dff50b5feeba454eacf 100644 (file)
  * course, only if the interrupt holdoff counter is zero). See the
  * related code for details.
  *
+ * A lost connection is handled similarly, although the loss of connection
+ * does not raise a signal, but is detected when we fail to write to the
+ * socket. If there was a signal for a broken connection, we could make use of
+ * it by setting ClientConnectionLost in the signal handler.
+ *
  * A related, but conceptually distinct, mechanism is the "critical section"
  * mechanism.  A critical section not only holds off cancel/die interrupts,
  * but causes any ereport(ERROR) or ereport(FATAL) to become ereport(PANIC)
@@ -70,6 +75,8 @@ extern PGDLLIMPORT volatile bool InterruptPending;
 extern volatile bool QueryCancelPending;
 extern volatile bool ProcDiePending;
 
+extern volatile bool ClientConnectionLost;
+
 /* these are marked volatile because they are examined by signal handlers: */
 extern volatile bool ImmediateInterruptOK;
 extern PGDLLIMPORT volatile uint32 InterruptHoldoffCount;