If we fail to fork a new backend process, (try to) report the failure
authorTom Lane
Sun, 6 Jan 2002 21:40:02 +0000 (21:40 +0000)
committerTom Lane
Sun, 6 Jan 2002 21:40:02 +0000 (21:40 +0000)
to the client before closing the connection.  Before 7.2 this was done
correctly, but new code would simply close the connection with no report
to the client.

src/backend/postmaster/postmaster.c

index 4f97e7ef9a686f90820dca3f05f652bf9b04de3a..f248019d0abdcd885e7226c00cb08e905e832c35 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.262 2001/12/04 16:17:48 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.263 2002/01/06 21:40:02 tgl Exp $
  *
  * NOTES
  *
@@ -249,6 +249,7 @@ static int  BackendStartup(Port *port);
 static int ProcessStartupPacket(Port *port, bool SSLdone);
 static void processCancelRequest(Port *port, void *pkt);
 static int initMasks(fd_set *rmask, fd_set *wmask);
+static void report_fork_failure_to_client(Port *port, int errnum);
 enum CAC_state
 {
    CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY
@@ -1864,11 +1865,11 @@ BackendStartup(Port *port)
    {
        int         status;
 
-       free(bn);
 #ifdef __BEOS__
        /* Specific beos backend startup actions */
        beos_backend_startup();
 #endif
+       free(bn);
 
        status = DoBackend(port);
        if (status != 0)
@@ -1883,13 +1884,16 @@ BackendStartup(Port *port)
    /* in parent, error */
    if (pid < 0)
    {
-       free(bn);
+       int         save_errno = errno;
+
 #ifdef __BEOS__
        /* Specific beos backend startup actions */
        beos_backend_startup_failed();
 #endif
+       free(bn);
        elog(DEBUG, "connection startup failed (fork failure): %s",
-            strerror(errno));
+            strerror(save_errno));
+       report_fork_failure_to_client(port, save_errno);
        return STATUS_ERROR;
    }
 
@@ -1910,6 +1914,40 @@ BackendStartup(Port *port)
 }
 
 
+/*
+ * Try to report backend fork() failure to client before we close the
+ * connection.  Since we do not care to risk blocking the postmaster on
+ * this connection, we set the connection to non-blocking and try only once.
+ *
+ * This is grungy special-purpose code; we cannot use backend libpq since
+ * it's not up and running.
+ */
+static void
+report_fork_failure_to_client(Port *port, int errnum)
+{
+   char        buffer[1000];
+#ifdef __BEOS__
+   int         on = 1;
+#endif
+
+   /* Format the error message packet */
+   snprintf(buffer, sizeof(buffer), "E%s%s\n",
+            gettext("Server process fork() failed: "),
+            strerror(errnum));
+
+   /* Set port to non-blocking.  Don't do send() if this fails */
+#ifdef __BEOS__
+   if (ioctl(port->sock, FIONBIO, &on) != 0)
+       return;
+#else
+   if (fcntl(port->sock, F_SETFL, O_NONBLOCK) < 0)
+       return;
+#endif
+
+   send(port->sock, buffer, strlen(buffer)+1, 0);
+}
+
+
 /*
  * split_opts -- split a string of options and append it to an argv array
  *