process startup: Split single user code out of PostgresMain().
authorAndres Freund <andres@anarazel.de>
Wed, 8 Sep 2021 19:19:50 +0000 (12:19 -0700)
committerAndres Freund <andres@anarazel.de>
Sat, 18 Sep 2021 02:56:47 +0000 (19:56 -0700)
It was harder than necessary to understand PostgresMain() because the code for
a normal backend was interspersed with single-user mode specific code. Split
most of the single-user mode code into its own function
PostgresSingleUserMain(), that does all the necessary setup for single-user
mode, and then hands off after that to PostgresMain().

There still is some single-user mode code in InitPostgres(), and it'd likely
be worth moving at least some of it out. But that's for later.

Reviewed-By: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Author: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/20210802164124.ufo5buo4apl6yuvs@alap3.anarazel.de

src/backend/main/main.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/include/tcop/tcopprot.h

index 3a2a0d598cd967ba817f486545502101627c3197..ad84a45e28c02072a1705f24e2150f44846b49d3 100644 (file)
@@ -192,9 +192,8 @@ main(int argc, char *argv[])
        else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
                GucInfoMain();
        else if (argc > 1 && strcmp(argv[1], "--single") == 0)
-               PostgresMain(argc, argv,
-                                        NULL,          /* no dbname */
-                                        strdup(get_user_name_or_exit(progname)));
+               PostgresSingleUserMain(argc, argv,
+                                                          strdup(get_user_name_or_exit(progname)));
        else
                PostmasterMain(argc, argv);
        /* the functions above should not return */
index 2ab7ed7dc395be2182bd7473866b59bce321716c..e2a76ba0558cb427129c8ae0cedc1f17716e7294 100644 (file)
@@ -4551,19 +4551,13 @@ BackendInitialize(Port *port)
 static void
 BackendRun(Port *port)
 {
-       char       *av[2];
-       const int       ac = 1;
-
-       av[0] = "postgres";
-       av[1] = NULL;
-
        /*
         * Make sure we aren't in PostmasterContext anymore.  (We can't delete it
         * just yet, though, because InitPostgres will need the HBA data.)
         */
        MemoryContextSwitchTo(TopMemoryContext);
 
-       PostgresMain(ac, av, port->database_name, port->user_name);
+       PostgresMain(port->database_name, port->user_name);
 }
 
 
index d85e10d9cef055cacf7d67f68630c39c5574ad1f..0775abe35de497a82654a3d54b4bdc2a48a9a85b 100644 (file)
@@ -3654,7 +3654,7 @@ get_stats_option_name(const char *arg)
 
 /* ----------------------------------------------------------------
  * process_postgres_switches
- *        Parse command line arguments for PostgresMain
+ *        Parse command line arguments for backends
  *
  * This is called twice, once for the "secure" options coming from the
  * postmaster or command line, and once for the "insecure" options coming
@@ -3915,40 +3915,30 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
 }
 
 
-/* ----------------------------------------------------------------
- * PostgresMain
- *        postgres main loop -- all backends, interactive or otherwise start here
+/*
+ * PostgresSingleUserMain
+ *     Entry point for single user mode. argc/argv are the command line
+ *     arguments to be used.
  *
- * argc/argv are the command line arguments to be used.  (When being forked
- * by the postmaster, these are not the original argv array of the process.)
- * dbname is the name of the database to connect to, or NULL if the database
- * name should be extracted from the command line arguments or defaulted.
- * username is the PostgreSQL user name to be used for the session.
- * ----------------------------------------------------------------
+ * Performs single user specific setup then calls PostgresMain() to actually
+ * process queries. Single user mode specific setup should go here, rather
+ * than PostgresMain() or InitPostgres() when reasonably possible.
  */
 void
-PostgresMain(int argc, char *argv[],
-                        const char *dbname,
-                        const char *username)
+PostgresSingleUserMain(int argc, char *argv[],
+                                          const char *username)
 {
-       int                     firstchar;
-       StringInfoData input_message;
-       sigjmp_buf      local_sigjmp_buf;
-       volatile bool send_ready_for_query = true;
-       bool            idle_in_transaction_timeout_enabled = false;
-       bool            idle_session_timeout_enabled = false;
+       const char *dbname = NULL;
 
-       /* Initialize startup process environment if necessary. */
-       if (!IsUnderPostmaster)
-               InitStandaloneProcess(argv[0]);
+       Assert(!IsUnderPostmaster);
 
-       SetProcessingMode(InitProcessing);
+       /* Initialize startup process environment. */
+       InitStandaloneProcess(argv[0]);
 
        /*
         * Set default values for command-line options.
         */
-       if (!IsUnderPostmaster)
-               InitializeGUCOptions();
+       InitializeGUCOptions();
 
        /*
         * Parse command-line options.
@@ -3966,12 +3956,75 @@ PostgresMain(int argc, char *argv[],
                                                        progname)));
        }
 
-       /* Acquire configuration parameters, unless inherited from postmaster */
-       if (!IsUnderPostmaster)
-       {
-               if (!SelectConfigFiles(userDoption, progname))
-                       proc_exit(1);
-       }
+       /* Acquire configuration parameters */
+       if (!SelectConfigFiles(userDoption, progname))
+               proc_exit(1);
+
+       /*
+        * Validate we have been given a reasonable-looking DataDir and change
+        * into it.
+        */
+       checkDataDir();
+       ChangeToDataDir();
+
+       /*
+        * Create lockfile for data directory.
+        */
+       CreateDataDirLockFile(false);
+
+       /* read control file (error checking and contains config ) */
+       LocalProcessControlFile(false);
+
+       /* Initialize MaxBackends */
+       InitializeMaxBackends();
+
+       CreateSharedMemoryAndSemaphores();
+
+       /*
+        * Remember stand-alone backend startup time,roughly at the same point
+        * during startup that postmaster does so.
+        */
+       PgStartTime = GetCurrentTimestamp();
+
+       /*
+        * Create a per-backend PGPROC struct in shared memory. We must do this
+        * before we can use LWLocks.
+        */
+       InitProcess();
+
+       /*
+        * Now that sufficient infrastructure has been initialized, PostgresMain()
+        * can do the rest.
+        */
+       PostgresMain(dbname, username);
+}
+
+
+/* ----------------------------------------------------------------
+ * PostgresMain
+ *        postgres main loop -- all backends, interactive or otherwise loop here
+ *
+ * dbname is the name of the database to connect to, username is the
+ * PostgreSQL user name to be used for the session.
+ *
+ * NB: Single user mode specific setup should go to PostgresSingleUserMain()
+ * if reasonably possible.
+ * ----------------------------------------------------------------
+ */
+void
+PostgresMain(const char *dbname, const char *username)
+{
+       int                     firstchar;
+       StringInfoData input_message;
+       sigjmp_buf      local_sigjmp_buf;
+       volatile bool send_ready_for_query = true;
+       bool            idle_in_transaction_timeout_enabled = false;
+       bool            idle_session_timeout_enabled = false;
+
+       AssertArg(dbname != NULL);
+       AssertArg(username != NULL);
+
+       SetProcessingMode(InitProcessing);
 
        /*
         * Set up signal handlers.  (InitPostmasterChild or InitStandaloneProcess
@@ -4029,43 +4082,6 @@ PostgresMain(int argc, char *argv[],
                                                                         * platforms */
        }
 
-       if (!IsUnderPostmaster)
-       {
-               /*
-                * Validate we have been given a reasonable-looking DataDir (if under
-                * postmaster, assume postmaster did this already).
-                */
-               checkDataDir();
-
-               /* Change into DataDir (if under postmaster, was done already) */
-               ChangeToDataDir();
-
-               /*
-                * Create lockfile for data directory.
-                */
-               CreateDataDirLockFile(false);
-
-               /* read control file (error checking and contains config ) */
-               LocalProcessControlFile(false);
-
-               /* Initialize MaxBackends (if under postmaster, was done already) */
-               InitializeMaxBackends();
-
-               CreateSharedMemoryAndSemaphores();
-
-               /*
-                * Remember stand-alone backend startup time, roughly at the same
-                * point during startup that postmaster does so.
-                */
-               PgStartTime = GetCurrentTimestamp();
-
-               /*
-                * Create a per-backend PGPROC struct in shared memory. We must do
-                * this before we can use LWLocks.
-                */
-               InitProcess();
-       }
-
        /* Early initialization */
        BaseInit();
 
index 968345404e54d7f559c7cfe086d4b1f036986342..5c77075aeddb1f9c43eb355acb8e163cfee24d1d 100644 (file)
@@ -75,8 +75,9 @@ extern void ProcessClientWriteInterrupt(bool blocked);
 
 extern void process_postgres_switches(int argc, char *argv[],
                                                                          GucContext ctx, const char **dbname);
-extern void PostgresMain(int argc, char *argv[],
-                                                const char *dbname,
+extern void PostgresSingleUserMain(int argc, char *argv[],
+                                                                  const char *username) pg_attribute_noreturn();
+extern void PostgresMain(const char *dbname,
                                                 const char *username) pg_attribute_noreturn();
 extern long get_stack_depth_rlimit(void);
 extern void ResetUsage(void);