]> granicus.if.org Git - postgresql/commitdiff
Include the first valid listen address in pg_ctl to improve server start
authorBruce Momjian <bruce@momjian.us>
Fri, 31 Dec 2010 22:24:26 +0000 (17:24 -0500)
committerBruce Momjian <bruce@momjian.us>
Fri, 31 Dec 2010 22:25:02 +0000 (17:25 -0500)
"wait" detection and add postmaster start time to help determine if the
postmaster is actually using the specified data directory.

doc/src/sgml/storage.sgml
src/backend/port/ipc_test.c
src/backend/port/sysv_shmem.c
src/backend/postmaster/postmaster.c
src/backend/utils/init/miscinit.c
src/bin/pg_ctl/pg_ctl.c
src/include/miscadmin.h

index 430df4a8438af55ee071cef9db1586237cb7c084..746a48219fd37b7c9c334625f938193cab745004 100644 (file)
@@ -117,8 +117,9 @@ last started with</entry>
 <row>
  <entry><filename>postmaster.pid</></entry>
  <entry>A lock file recording the current postmaster process id (PID),
- cluster data directory, port number, Unix domain socket directory,
- and shared memory segment ID</entry>
+ postmaster start time, cluster data directory, port number, user-specified
+ Unix domain socket directory, first valid listen_address host, and
+ shared memory segment ID</entry>
 </row>
 
 </tbody>
index a003dc9c206a594fe5c6627a6d6e9b5c353c9549..461a7a65b2d19f04733ac952d5887e3cbbf4a49d 100644 (file)
@@ -104,7 +104,7 @@ on_exit_reset(void)
 }
 
 void
-RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
+AddToLockFile(int target_line, const char *str)
 {
 }
 
index d970eb299673d2cd2e29de9dd4310877ed7b4cbd..ff77099885131831984a1292821471a09f5be0e5 100644 (file)
@@ -198,9 +198,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
        /* Register on-exit routine to detach new segment before deleting */
        on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
 
-       /* Record key and ID in lockfile for data directory. */
-       RecordSharedMemoryInLockFile((unsigned long) memKey,
-                                                                (unsigned long) shmid);
+       /*
+        * Append record key and ID in lockfile for data directory. Format
+        * to try to keep it the same length.
+        */
+       {
+               char line[32];
+
+               sprintf(line, "%9lu %9lu\n", (unsigned long) memKey,
+                                                                        (unsigned long) shmid);
+               AddToLockFile(LOCK_FILE_LINES, line);
+       }
 
        return memAddress;
 }
index a46a323881de752ea46fc1bbd6816e0690fd795a..c1e553a85be542e97eb45f85dff316b95acdfbe8 100644 (file)
@@ -483,7 +483,8 @@ PostmasterMain(int argc, char *argv[])
        int                     status;
        char       *userDoption = NULL;
        int                     i;
-
+       bool            connection_line_output = false;
+       
        MyProcPid = PostmasterPid = getpid();
 
        MyStartTime = time(NULL);
@@ -860,10 +861,22 @@ PostmasterMain(int argc, char *argv[])
                                                                                  UnixSocketDir,
                                                                                  ListenSocket, MAXLISTEN);
                        else
+                       {
                                status = StreamServerPort(AF_UNSPEC, curhost,
                                                                                  (unsigned short) PostPortNumber,
                                                                                  UnixSocketDir,
                                                                                  ListenSocket, MAXLISTEN);
+                               /* must supply a valid listen_address for PQping() */
+                               if (!connection_line_output)
+                               {
+                                       char line[MAXPGPATH + 2];
+
+                                       sprintf(line, "%s\n", curhost);
+                                       AddToLockFile(LOCK_FILE_LINES - 1, line);
+                                       connection_line_output = true;
+                               }
+                       }
+                               
                        if (status == STATUS_OK)
                                success++;
                        else
@@ -880,6 +893,10 @@ PostmasterMain(int argc, char *argv[])
                pfree(rawstring);
        }
 
+       /* Supply an empty listen_address line for PQping() */
+       if (!connection_line_output)
+               AddToLockFile(LOCK_FILE_LINES - 1, "\n");
+
 #ifdef USE_BONJOUR
        /* Register for Bonjour only if we opened TCP socket(s) */
        if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET)
index 0d5ffb0a8e59bef456da6dee282fb74bd8691cb7..27679259e4798263e7da0f79efe75e872dcd8853 100644 (file)
 
 
 #define DIRECTORY_LOCK_FILE            "postmaster.pid"
-
+/*
+ *     The lock file contents are:
+ *
+ * line #
+ *             1       pid
+ *             2       postmaster start time
+ *             3       data directory
+ *             4       port #
+ *             5       user-specified socket directory
+ *                     (the lines below are added later)
+ *             6       first valid listen_address
+ *             7       shared memory key
+ */
+       
 ProcessingMode Mode = InitProcessing;
 
 /* Note: we rely on this to initialize as zeroes */
@@ -678,7 +691,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
                           bool isDDLock, const char *refName)
 {
        int                     fd;
-       char            buffer[MAXPGPATH * 2 + 256];
+       char            buffer[MAXPGPATH * 3 + 256];
        int                     ntries;
        int                     len;
        int                     encoded_pid;
@@ -845,11 +858,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
                if (isDDLock)
                {
                        char       *ptr = buffer;
-                       unsigned long id1,
-                                               id2;
+                       unsigned long id1, id2;
                        int lineno;
 
-                       for (lineno = 1; lineno <= 4; lineno++)
+                       for (lineno = 1; lineno <= LOCK_FILE_LINES - 1; lineno++)
                        {
                                if ((ptr = strchr(ptr, '\n')) == NULL)
                                {
@@ -893,9 +905,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
        /*
         * Successfully created the file, now fill it.
         */
-       snprintf(buffer, sizeof(buffer), "%d\n%s\n%d\n%s\n",
+       snprintf(buffer, sizeof(buffer), "%d\n%ld\n%s\n%d\n%s\n",
                         amPostmaster ? (int) my_pid : -((int) my_pid),
-                        DataDir, PostPortNumber, UnixSocketDir);
+                        (long) MyStartTime, DataDir, PostPortNumber,
+                        UnixSocketDir);
        errno = 0;
        if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
        {
@@ -1004,24 +1017,19 @@ TouchSocketLockFile(void)
        }
 }
 
+
 /*
- * Append information about a shared memory segment to the data directory
- * lock file.
- *
- * This may be called multiple times in the life of a postmaster, if we
- * delete and recreate shmem due to backend crash.     Therefore, be prepared
- * to overwrite existing information.  (As of 7.1, a postmaster only creates
- * one shm seg at a time; but for the purposes here, if we did have more than
- * one then any one of them would do anyway.)
+ * Add lines to the data directory lock file.  This erases all following
+ * lines, but that is OK because lines are added in order.
  */
 void
-RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
+AddToLockFile(int target_line, const char *str)
 {
        int                     fd;
        int                     len;
        int                     lineno;
        char       *ptr;
-       char            buffer[MAXPGPATH * 2 + 256];
+       char            buffer[MAXPGPATH * 3 + 256];
 
        fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
        if (fd < 0)
@@ -1048,7 +1056,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
         * Skip over first four lines (PID, pgdata, portnum, socketdir).
         */
        ptr = buffer;
-       for (lineno = 1; lineno <= 4; lineno++)
+       for (lineno = 1; lineno < target_line; lineno++)
        {
                if ((ptr = strchr(ptr, '\n')) == NULL)
                {
@@ -1059,11 +1067,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
                ptr++;
        }
        
-       /*
-        * Append key information.      Format to try to keep it the same length
-        * always (trailing junk won't hurt, but might confuse humans).
-        */
-       sprintf(ptr, "%9lu %9lu\n", id1, id2);
+       strlcat(buffer, str, sizeof(buffer));
 
        /*
         * And rewrite the data.  Since we write in a single kernel call, this
index 5e1b7728fcd3d9d829b8cf8c4f56d20184085697..92ea514f1dbf4bfeda2e28881d16884e64820680 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <locale.h>
 #include <signal.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -138,6 +139,7 @@ static void read_post_opts(void);
 
 static PGPing test_postmaster_connection(bool);
 static bool postmaster_is_alive(pid_t pid);
+static time_t start_time;
 
 static char postopts_file[MAXPGPATH];
 static char pid_file[MAXPGPATH];
@@ -404,13 +406,13 @@ static PGPing
 test_postmaster_connection(bool do_checkpoint)
 {
        int                     portnum = 0;
-       char            socket_dir[MAXPGPATH];
+       char            host_str[MAXPGPATH];
        char            connstr[MAXPGPATH + 256];
        PGPing          ret = PQPING_OK;        /* assume success for wait == zero */
        char      **optlines;
        int                     i;
 
-       socket_dir[0] = '\0';
+       host_str[0] = '\0';
        connstr[0] = '\0';
        
        for (i = 0; i < wait_seconds; i++)
@@ -425,13 +427,14 @@ test_postmaster_connection(bool do_checkpoint)
                         *              0       lock file created but status not written
                         *              2       pre-9.1 server, shared memory not created
                         *              3       pre-9.1 server, shared memory created
-                        *              4       9.1+ server, shared memory not created
-                        *              5       9.1+ server, shared memory created
+                        *              5       9.1+ server, listen host not created
+                        *              6       9.1+ server, shared memory not created
+                        *              7       9.1+ server, shared memory created
                         *
                         *      For pre-9.1 Unix servers, we grab the port number from the
                         *      shmem key (first value on line 3).  Pre-9.1 Win32 has no
-                        *      written shmem key, so we fail.  9.1+ writes both the port
-                        *      number and socket address in the file for us to use.
+                        *      written shmem key, so we fail.  9.1+ writes connection
+                        *      information in the file for us to use.
                         *      (PG_VERSION could also have told us the major version.)
                         */
                
@@ -439,7 +442,10 @@ test_postmaster_connection(bool do_checkpoint)
                        if ((optlines = readfile(pid_file)) != NULL &&
                                optlines[0] != NULL &&
                                optlines[1] != NULL &&
-                               optlines[2] != NULL)
+                               optlines[2] != NULL &&
+                               /* pre-9.1 server or listen_address line is present? */
+                               (optlines[3] == NULL ||
+                                optlines[5] != NULL))
                        {                               
                                /* A 3-line file? */
                                if (optlines[3] == NULL)
@@ -459,31 +465,53 @@ test_postmaster_connection(bool do_checkpoint)
                                                return PQPING_NO_ATTEMPT;
                                        }
                                }
-                               else    /* 9.1+ server */
+                               else
                                {
-                                       portnum = atoi(optlines[2]);
-       
-                                       /* Get socket directory, if specified. */
-                                       if (optlines[3][0] != '\n')
+                                       /*
+                                        *      Easy check to see if we are looking at the right
+                                        *      data directory:  Is the postmaster older than this
+                                        *      execution of pg_ctl?  Subtract 2 seconds to account
+                                        *      for possible clock skew between pg_ctl and the
+                                        *      postmaster.
+                                        */
+                                       if (atol(optlines[1]) < start_time - 2)
                                        {
-                                               /*
-                                                *      While unix_socket_directory can accept relative
-                                                *      directories, libpq's host must have a leading slash
-                                                *      to indicate a socket directory.
-                                                */
-                                               if (optlines[3][0] != '/')
-                                               {
-                                                       write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
-                                                                                progname);
-                                                       return PQPING_NO_ATTEMPT;
-                                               }
-                                               strlcpy(socket_dir, optlines[3], MAXPGPATH);
-                                               /* remove newline */
-                                               if (strchr(socket_dir, '\n') != NULL)
-                                                       *strchr(socket_dir, '\n') = '\0';
+                                               write_stderr(_("%s: this data directory is running an older postmaster\n"),
+                                                                        progname);
+                                               return PQPING_NO_ATTEMPT;
                                        }
-                               }
+                                               
+                                       portnum = atoi(optlines[3]);
 
+                                       /*
+                                        *      Determine the proper host string to use.
+                                        */
+#ifdef HAVE_UNIX_SOCKETS
+                                       /*
+                                        *      Use socket directory, if specified.  We assume if we
+                                        *      have unix sockets, the server does too because we
+                                        *      just started the postmaster.
+                                        */
+                                       /*
+                                        *      While unix_socket_directory can accept relative
+                                        *      directories, libpq's host must have a leading slash
+                                        *      to indicate a socket directory.
+                                        */
+                                       if (optlines[4][0] != '\n' && optlines[4][0] != '/')
+                                       {
+                                               write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
+                                                                        progname);
+                                               return PQPING_NO_ATTEMPT;
+                                       }
+                                       strlcpy(host_str, optlines[4], sizeof(host_str));
+#else
+                                       strlcpy(host_str, optlines[5], sizeof(host_str));
+#endif
+                                       /* remove newline */
+                                       if (strchr(host_str, '\n') != NULL)
+                                               *strchr(host_str, '\n') = '\0';
+                               }
+                               
                                /*
                                 * We need to set connect_timeout otherwise on Windows the
                                 * Service Control Manager (SCM) will probably timeout first.
@@ -491,9 +519,9 @@ test_postmaster_connection(bool do_checkpoint)
                                snprintf(connstr, sizeof(connstr),
                                                 "dbname=postgres port=%d connect_timeout=5", portnum);
 
-                               if (socket_dir[0] != '\0')
+                               if (host_str[0] != '\0')
                                        snprintf(connstr + strlen(connstr), sizeof(connstr) - strlen(connstr),
-                                               " host='%s'", socket_dir);
+                                               " host='%s'", host_str);
                        }
                }
 
@@ -1756,6 +1784,7 @@ main(int argc, char **argv)
 
        progname = get_progname(argv[0]);
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
+       start_time = time(NULL);
 
        /*
         * save argv[0] so do_start() can look for the postmaster if necessary. we
index ddba50cafae895e44cdc97e88736ce1596bd6493..b2a8d820793d7534e6d84130584f6c53473398bc 100644 (file)
@@ -348,11 +348,11 @@ extern PGDLLIMPORT bool process_shared_preload_libraries_in_progress;
 extern char *shared_preload_libraries_string;
 extern char *local_preload_libraries_string;
 
+#define LOCK_FILE_LINES                7
 extern void CreateDataDirLockFile(bool amPostmaster);
 extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
 extern void TouchSocketLockFile(void);
-extern void RecordSharedMemoryInLockFile(unsigned long id1,
-                                                        unsigned long id2);
+extern void AddToLockFile(int target_line, const char *str);
 extern void ValidatePgVersion(const char *path);
 extern void process_shared_preload_libraries(void);
 extern void process_local_preload_libraries(void);