process startup: Split single user code out of PostgresMain().
authorAndres Freund
Wed, 8 Sep 2021 19:19:50 +0000 (12:19 -0700)
committerAndres Freund
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
Author: Andres Freund 
Discussion: https://postgr.es/m/20210802164124[email protected]

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);