Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
In libpq for Windows, call WSAStartup once and WSACleanup not at all.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Oct 2020 15:23:52 +0000 (11:23 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Oct 2020 15:23:52 +0000 (11:23 -0400)
The Windows documentation insists that every WSAStartup call should
have a matching WSACleanup call.  However, if that ever had actual
relevance, it wasn't in this century.  Every remotely-modern Windows
kernel is capable of cleaning up when a process exits without doing
that, and must be so to avoid resource leaks in case of a process
crash.  Moreover, Postgres backends have done WSAStartup without
WSACleanup since commit 4cdf51e64 in 2004, and we've never seen any
indication of a problem with that.

libpq's habit of doing WSAStartup during connection start and
WSACleanup during shutdown is also rather inefficient, since a
series of non-overlapping connection requests leads to repeated,
quite expensive DLL unload/reload cycles.  We document a workaround
for that (having the application call WSAStartup for itself), but
that's just a kluge.  It's also worth noting that it's far from
uncommon for applications to exit without doing PQfinish, and
we've not heard reports of trouble from that either.

However, the real reason for acting on this is that recent
experiments by Alexander Lakhin show that calling WSACleanup
during PQfinish is triggering the symptom we occasionally see
that a process using libpq fails to emit expected stdio output.

Therefore, let's change libpq so that it calls WSAStartup only
once per process, during the first connection attempt, and never
calls WSACleanup at all.

While at it, get rid of the only other WSACleanup call in our code
tree, in pg_dump/parallel.c; that presumably is equally useless.

Back-patch of HEAD commit 7d00a6b2d.

Discussion: https://postgr.es/m/ac976d8c-03df-d6b8-025c-15a2de8d9af1@postgrespro.ru

doc/src/sgml/libpq.sgml
src/bin/pg_dump/parallel.c
src/interfaces/libpq/fe-connect.c

index 9903cdef640265713cb8d80ef719d3d301be0032..c51fe03d9d85481ceaee5a87a4d4920fbbe6ab4b 100644 (file)
     </para>
    </warning>
 
-   <note>
-    <para>
-     On Windows, there is a way to improve performance if a single
-     database connection is repeatedly started and shutdown.  Internally,
-     libpq calls <function>WSAStartup()</> and <function>WSACleanup()</> for connection startup
-     and shutdown, respectively.  <function>WSAStartup()</> increments an internal
-     Windows library reference count which is decremented by <function>WSACleanup()</>.
-     When the reference count is just one, calling <function>WSACleanup()</> frees
-     all resources and all DLLs are unloaded.  This is an expensive
-     operation.  To avoid this, an application can manually call
-     <function>WSAStartup()</> so resources will not be freed when the last database
-     connection is closed.
-    </para>
-   </note>
-
    <variablelist>
     <varlistentry id="libpq-pqconnectdbparams">
      <term><function>PQconnectdbParams</function><indexterm><primary>PQconnectdbParams</></></term>
index 4eff4b2a19af5d5a15704ad895efa7ed46b26957..14e45cfbfff5c7e97686c2bcf37d81b0ab63c05e 100644 (file)
@@ -232,19 +232,6 @@ static char *readMessageFromPipe(int fd);
    (strcmp(msg, pattern) == 0)
 
 
-/*
- * Shutdown callback to clean up socket access
- */
-#ifdef WIN32
-static void
-shutdown_parallel_dump_utils(int code, void *unused)
-{
-   /* Call the cleanup function only from the main thread */
-   if (mainThreadId == GetCurrentThreadId())
-       WSACleanup();
-}
-#endif
-
 /*
  * Initialize parallel dump support --- should be called early in process
  * startup.  (Currently, this is called whether or not we intend parallel
@@ -270,8 +257,7 @@ init_parallel_dump_utils(void)
            fprintf(stderr, _("%s: WSAStartup failed: %d\n"), progname, err);
            exit_nicely(1);
        }
-       /* ... and arrange to shut it down at exit */
-       on_exit_nicely(shutdown_parallel_dump_utils, NULL);
+
        parallel_init_done = true;
    }
 #endif
index 80786c0d924e05e2ad641791a9f4040a617dc115..18c09472bed462ef25080fa01073927d2b440e0c 100644 (file)
@@ -3436,23 +3436,30 @@ makeEmptyPGconn(void)
 #ifdef WIN32
 
    /*
-    * Make sure socket support is up and running.
+    * Make sure socket support is up and running in this process.
+    *
+    * Note: the Windows documentation says that we should eventually do a
+    * matching WSACleanup() call, but experience suggests that that is at
+    * least as likely to cause problems as fix them.  So we don't.
     */
-   WSADATA     wsaData;
+   static bool wsastartup_done = false;
 
-   if (WSAStartup(MAKEWORD(1, 1), &wsaData))
-       return NULL;
+   if (!wsastartup_done)
+   {
+       WSADATA     wsaData;
+
+       if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
+           return NULL;
+       wsastartup_done = true;
+   }
+
+   /* Forget any earlier error */
    WSASetLastError(0);
-#endif
+#endif                         /* WIN32 */
 
    conn = (PGconn *) malloc(sizeof(PGconn));
    if (conn == NULL)
-   {
-#ifdef WIN32
-       WSACleanup();
-#endif
        return conn;
-   }
 
    /* Zero all pointers and booleans */
    MemSet(conn, 0, sizeof(PGconn));
@@ -3620,10 +3627,6 @@ freePGconn(PGconn *conn)
    termPQExpBuffer(&conn->workBuffer);
 
    free(conn);
-
-#ifdef WIN32
-   WSACleanup();
-#endif
 }
 
 /*