Postpone pg_timezone_initialize() until after creation of postmaster.pid,
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Oct 2005 20:06:03 +0000 (20:06 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 20 Oct 2005 20:06:03 +0000 (20:06 +0000)
since it can take a fair amount of time and this can confuse boot scripts
that expect postmaster.pid to appear quickly.  Move initialization of SSL
library and preloaded libraries to after that point, too, just for luck.
Per reports from Tony Caduto and others.

src/backend/bootstrap/bootstrap.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/utils/misc/guc.c

index 626db3da3a22af8f4277bba9a2bfeb0fe3e51c4b..80e1ab5eef103a68a224ea1928a643733da02425 100644 (file)
@@ -354,6 +354,8 @@ BootstrapMain(int argc, char *argv[])
        {
                if (!SelectConfigFiles(userDoption, progname))
                        proc_exit(1);
+               /* If timezone is not set, determine what the OS uses */
+               pg_timezone_initialize();
        }
 
        /* Validate we have been given a reasonable-looking DataDir */
index 835e72b5f195587c97bb290c28ef2c4962acdf63..0360cc468e26427dde3b5710d7f58ecca13cc108 100644 (file)
@@ -613,7 +613,8 @@ PostmasterMain(int argc, char *argv[])
        }
 
        /*
-        * Other one-time internal sanity checks can go here.
+        * Other one-time internal sanity checks can go here, if they are fast.
+        * (Put any slow processing further down, after postmaster.pid creation.)
         */
        if (!CheckDateTokenTables())
        {
@@ -655,21 +656,6 @@ PostmasterMain(int argc, char *argv[])
                                         progname)));
 #endif
 
-       /*
-        * Initialize SSL library, if specified.
-        */
-#ifdef USE_SSL
-       if (EnableSSL)
-               secure_initialize();
-#endif
-
-       /*
-        * process any libraries that should be preloaded and optionally
-        * pre-initialized
-        */
-       if (preload_libraries_string)
-               process_preload_libraries(preload_libraries_string);
-
        /*
         * Fork away from controlling terminal, if -S specified.
         *
@@ -690,6 +676,30 @@ PostmasterMain(int argc, char *argv[])
         */
        CreateDataDirLockFile(DataDir, true);
 
+       /*
+        * If timezone is not set, determine what the OS uses.  (In theory this
+        * should be done during GUC initialization, but because it can take as
+        * much as several seconds, we delay it until after we've created the
+        * postmaster.pid file.  This prevents problems with boot scripts that
+        * expect the pidfile to appear quickly.)
+        */
+       pg_timezone_initialize();
+
+       /*
+        * Initialize SSL library, if specified.
+        */
+#ifdef USE_SSL
+       if (EnableSSL)
+               secure_initialize();
+#endif
+
+       /*
+        * process any libraries that should be preloaded and optionally
+        * pre-initialized
+        */
+       if (preload_libraries_string)
+               process_preload_libraries(preload_libraries_string);
+
        /*
         * Remove old temporary files.  At this point there can be no other
         * Postgres processes running in this directory, so this should be
@@ -953,9 +963,32 @@ checkDataDir(void)
                                        DataDir)));
        }
 
+       /*
+        * Check that the directory belongs to my userid; if not, reject.
+        *
+        * This check is an essential part of the interlock that prevents two
+        * postmasters from starting in the same directory (see CreateLockFile()).
+        * Do not remove or weaken it.
+        *
+        * XXX can we safely enable this check on Windows?
+        */
+#if !defined(WIN32) && !defined(__CYGWIN__)
+       if (stat_buf.st_uid != geteuid())
+               ereport(FATAL,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("data directory \"%s\" has wrong ownership",
+                                               DataDir),
+                                errhint("The server must be started by the user that owns the data directory.")));
+#endif
+
        /*
         * Check if the directory has group or world access.  If so, reject.
         *
+        * It would be possible to allow weaker constraints (for example, allow
+        * group access) but we cannot make a general assumption that that is
+        * okay; for example there are platforms where nearly all users customarily
+        * belong to the same group.  Perhaps this test should be configurable.
+        *
         * XXX temporarily suppress check when on Windows, because there may not
         * be proper support for Unix-y file permissions.  Need to think of a
         * reasonable check to apply on Windows.
@@ -2508,7 +2541,7 @@ report_fork_failure_to_client(Port *port, int errnum)
                         strerror(errnum));
 
        /* Set port to non-blocking.  Don't do send() if this fails */
-       if (!set_noblock(port->sock))
+       if (!pg_set_noblock(port->sock))
                return;
 
        send(port->sock, buffer, strlen(buffer) + 1, 0);
index cac60f9f3d5f1fee89b4a35d05bb4e00094ea2b8..ca16f97ece66908092c7050d86fec197a61adceb 100644 (file)
@@ -113,6 +113,13 @@ static volatile sig_atomic_t got_SIGHUP = false;
  */
 static bool xact_started = false;
 
+/*
+ * Flag to indicate that we are doing the outer loop's read-from-client,
+ * as opposed to any random read from client that might happen within
+ * commands like COPY FROM STDIN.
+ */
+static bool DoingCommandRead = false;
+
 /*
  * Flags to implement skip-till-Sync-after-error behavior for messages of
  * the extended query protocol.
@@ -406,6 +413,52 @@ ReadCommand(StringInfo inBuf)
        return result;
 }
 
+/*
+ * prepare_for_client_read -- set up to possibly block on client input
+ *
+ * This must be called immediately before any low-level read from the
+ * client connection.  It is necessary to do it at a sufficiently low level
+ * that there won't be any other operations except the read kernel call
+ * itself between this call and the subsequent client_read_ended() call.
+ * In particular there mustn't be use of malloc() or other potentially
+ * non-reentrant libc functions.  This restriction makes it safe for us
+ * to allow interrupt service routines to execute nontrivial code while
+ * we are waiting for input.
+ */
+void
+prepare_for_client_read(void)
+{
+       if (DoingCommandRead)
+       {
+               /* Enable immediate processing of asynchronous signals */
+               EnableNotifyInterrupt();
+               EnableCatchupInterrupt();
+
+               /* Allow "die" interrupt to be processed while waiting */
+               ImmediateInterruptOK = true;
+
+               /* And don't forget to detect one that already arrived */
+               QueryCancelPending = false;
+               CHECK_FOR_INTERRUPTS();
+       }
+}
+
+/*
+ * client_read_ended -- get out of the client-input state
+ */
+void
+client_read_ended(void)
+{
+       if (DoingCommandRead)
+       {
+               ImmediateInterruptOK = false;
+               QueryCancelPending = false;             /* forget any CANCEL signal */
+
+               DisableNotifyInterrupt();
+               DisableCatchupInterrupt();
+       }
+}
+
 
 /*
  * Parse a query string and pass it through the rewriter.
@@ -495,7 +548,8 @@ pg_parse_query(const char *query_string)
                        if (IsA(parsetree, PrepareStmt))
                                parsetree = (Node *) (((PrepareStmt *) parsetree)->query);
 
-                       if (IsA(parsetree, SelectStmt))
+                       if (IsA(parsetree, SelectStmt) &&
+                               ((SelectStmt *) parsetree)->into == NULL)
                                continue;               /* optimization for frequent command */
 
                        if (log_statement == LOGSTMT_MOD &&
@@ -513,6 +567,7 @@ pg_parse_query(const char *query_string)
                        }
                        commandTag = CreateCommandTag(parsetree);
                        if (strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 ||
+                               IsA(parsetree, SelectStmt) || /* SELECT INTO, CREATE AS */
                                strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 ||
                                strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 ||
                                IsA(parsetree, GrantStmt) ||    /* GRANT or REVOKE */
@@ -2590,6 +2645,8 @@ PostgresMain(int argc, char *argv[], const char *username)
        {
                if (!SelectConfigFiles(userDoption, argv[0]))
                        proc_exit(1);
+               /* If timezone is not set, determine what the OS uses */
+               pg_timezone_initialize();
        }
 
        /*
@@ -2844,6 +2901,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                 * not in other exception-catching places since these interrupts
                 * are only enabled while we wait for client input.
                 */
+               DoingCommandRead = false;
                DisableNotifyInterrupt();
                DisableCatchupInterrupt();
 
@@ -2948,21 +3006,13 @@ PostgresMain(int argc, char *argv[], const char *username)
                }
 
                /*
-                * (2) deal with pending asynchronous NOTIFY from other backends,
-                * and enable async.c's signal handler to execute NOTIFY directly.
-                * Then set up other stuff needed before blocking for input.
+                * (2) Allow asynchronous signals to be executed immediately
+                * if they come in while we are waiting for client input.
+                * (This must be conditional since we don't want, say, reads on
+                * behalf of COPY FROM STDIN doing the same thing.)
                 */
-               QueryCancelPending = false;             /* forget any earlier CANCEL
-                                                                                * signal */
-
-               EnableNotifyInterrupt();
-               EnableCatchupInterrupt();
-
-               /* Allow "die" interrupt to be processed while waiting */
-               ImmediateInterruptOK = true;
-               /* and don't forget to detect one that already arrived */
-               QueryCancelPending = false;
-               CHECK_FOR_INTERRUPTS();
+               QueryCancelPending = false;             /* forget any earlier CANCEL signal */
+               DoingCommandRead = true;
 
                /*
                 * (3) read a command (loop blocks here)
@@ -2972,11 +3022,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                /*
                 * (4) disable async signal conditions again.
                 */
-               ImmediateInterruptOK = false;
-               QueryCancelPending = false;             /* forget any CANCEL signal */
-
-               DisableNotifyInterrupt();
-               DisableCatchupInterrupt();
+               DoingCommandRead = false;
 
                /*
                 * (5) check for any other interesting events that happened while
index f4dfc36557778c817853d12f076feed2350826f8..868fcbcca277077b96c7a858fe69ed6269803b99 100644 (file)
@@ -2584,9 +2584,6 @@ SelectConfigFiles(const char *userDoption, const char *progname)
 
        free(configdir);
 
-       /* If timezone is not set, determine what the OS uses */
-       pg_timezone_initialize();
-
        return true;
 }
 
@@ -4168,6 +4165,8 @@ DefineCustomIntVariable(
                                                const char *short_desc,
                                                const char *long_desc,
                                                int *valueAddr,
+                                               int minValue,
+                                               int maxValue,
                                                GucContext context,
                                                GucIntAssignHook assign_hook,
                                                GucShowHook show_hook)
@@ -4180,6 +4179,8 @@ DefineCustomIntVariable(
 
        var->variable = valueAddr;
        var->reset_val = *valueAddr;
+       var->min = minValue;
+       var->max = maxValue;
        var->assign_hook = assign_hook;
        var->show_hook = show_hook;
        define_custom_variable(&var->gen);
@@ -4191,6 +4192,8 @@ DefineCustomRealVariable(
                                                 const char *short_desc,
                                                 const char *long_desc,
                                                 double *valueAddr,
+                                                double minValue,
+                                                double maxValue,
                                                 GucContext context,
                                                 GucRealAssignHook assign_hook,
                                                 GucShowHook show_hook)
@@ -4203,6 +4206,8 @@ DefineCustomRealVariable(
 
        var->variable = valueAddr;
        var->reset_val = *valueAddr;
+       var->min = minValue;
+       var->max = maxValue;
        var->assign_hook = assign_hook;
        var->show_hook = show_hook;
        define_custom_variable(&var->gen);