On Windows, close the client socket explicitly during backend shutdown.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Dec 2021 22:14:43 +0000 (17:14 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Dec 2021 22:14:43 +0000 (17:14 -0500)
It turns out that this is necessary to keep Winsock from dropping any
not-yet-sent data, such as an error message explaining the reason for
process termination.  It's pretty weird that the implicit close done
by the kernel acts differently from an explicit close, but it's hard
to argue with experimental results.

Independently submitted by Alexander Lakhin and Lars Kanis (comments
by me, though).  Back-patch to all supported branches.

Discussion: https://postgr.es/m/90b34057-4176-7bb0-0dbb-9822a5f6425b@greiz-reinsdorf.de
Discussion: https://postgr.es/m/16678-253e48d34dc0c376@postgresql.org

src/backend/libpq/pqcomm.c

index 9ebba025cc7442a57387fdbcd6f2f6150bda15ca..96ab37c7d0ede11264b23fda1f283836a6512870 100644 (file)
@@ -277,15 +277,28 @@ socket_close(int code, Datum arg)
        secure_close(MyProcPort);
 
        /*
-        * Formerly we did an explicit close() here, but it seems better to
-        * leave the socket open until the process dies.  This allows clients
-        * to perform a "synchronous close" if they care --- wait till the
-        * transport layer reports connection closure, and you can be sure the
-        * backend has exited.
+        * On most platforms, we leave the socket open until the process dies.
+        * This allows clients to perform a "synchronous close" if they care
+        * --- wait till the transport layer reports connection closure, and
+        * you can be sure the backend has exited.  Saves a kernel call, too.
         *
-        * We do set sock to PGINVALID_SOCKET to prevent any further I/O,
-        * though.
+        * However, that does not work on Windows: if the kernel closes the
+        * socket it will invoke an "abortive shutdown" that discards any data
+        * not yet sent to the client.  (This is a flat-out violation of the
+        * TCP RFCs, but count on Microsoft not to care about that.)  To get
+        * the spec-compliant "graceful shutdown" behavior, we must invoke
+        * closesocket() explicitly.
+        *
+        * This code runs late enough during process shutdown that we should
+        * have finished all externally-visible shutdown activities, so that
+        * in principle it's good enough to act as a synchronous close on
+        * Windows too.  But it's a lot more fragile than the other way.
         */
+#ifdef WIN32
+       closesocket(MyProcPort->sock);
+#endif
+
+       /* In any case, set sock to PGINVALID_SOCKET to prevent further I/O */
        MyProcPort->sock = PGINVALID_SOCKET;
    }
 }