Commit 30aeda43 authored by Bruce Momjian's avatar Bruce Momjian

Include the first valid listen address in pg_ctl to improve server start

"wait" detection and add postmaster start time to help determine if the
postmaster is actually using the specified data directory.
parent 39c8dd66
...@@ -117,8 +117,9 @@ last started with</entry> ...@@ -117,8 +117,9 @@ last started with</entry>
<row> <row>
<entry><filename>postmaster.pid</></entry> <entry><filename>postmaster.pid</></entry>
<entry>A lock file recording the current postmaster process id (PID), <entry>A lock file recording the current postmaster process id (PID),
cluster data directory, port number, Unix domain socket directory, postmaster start time, cluster data directory, port number, user-specified
and shared memory segment ID</entry> Unix domain socket directory, first valid listen_address host, and
shared memory segment ID</entry>
</row> </row>
</tbody> </tbody>
......
...@@ -104,7 +104,7 @@ on_exit_reset(void) ...@@ -104,7 +104,7 @@ on_exit_reset(void)
} }
void void
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) AddToLockFile(int target_line, const char *str)
{ {
} }
......
...@@ -198,9 +198,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size) ...@@ -198,9 +198,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
/* Register on-exit routine to detach new segment before deleting */ /* Register on-exit routine to detach new segment before deleting */
on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress)); on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
/* Record key and ID in lockfile for data directory. */ /*
RecordSharedMemoryInLockFile((unsigned long) memKey, * Append record key and ID in lockfile for data directory. Format
(unsigned long) shmid); * 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; return memAddress;
} }
......
...@@ -483,7 +483,8 @@ PostmasterMain(int argc, char *argv[]) ...@@ -483,7 +483,8 @@ PostmasterMain(int argc, char *argv[])
int status; int status;
char *userDoption = NULL; char *userDoption = NULL;
int i; int i;
bool connection_line_output = false;
MyProcPid = PostmasterPid = getpid(); MyProcPid = PostmasterPid = getpid();
MyStartTime = time(NULL); MyStartTime = time(NULL);
...@@ -860,10 +861,22 @@ PostmasterMain(int argc, char *argv[]) ...@@ -860,10 +861,22 @@ PostmasterMain(int argc, char *argv[])
UnixSocketDir, UnixSocketDir,
ListenSocket, MAXLISTEN); ListenSocket, MAXLISTEN);
else else
{
status = StreamServerPort(AF_UNSPEC, curhost, status = StreamServerPort(AF_UNSPEC, curhost,
(unsigned short) PostPortNumber, (unsigned short) PostPortNumber,
UnixSocketDir, UnixSocketDir,
ListenSocket, MAXLISTEN); 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) if (status == STATUS_OK)
success++; success++;
else else
...@@ -880,6 +893,10 @@ PostmasterMain(int argc, char *argv[]) ...@@ -880,6 +893,10 @@ PostmasterMain(int argc, char *argv[])
pfree(rawstring); pfree(rawstring);
} }
/* Supply an empty listen_address line for PQping() */
if (!connection_line_output)
AddToLockFile(LOCK_FILE_LINES - 1, "\n");
#ifdef USE_BONJOUR #ifdef USE_BONJOUR
/* Register for Bonjour only if we opened TCP socket(s) */ /* Register for Bonjour only if we opened TCP socket(s) */
if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET) if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET)
......
...@@ -46,7 +46,20 @@ ...@@ -46,7 +46,20 @@
#define DIRECTORY_LOCK_FILE "postmaster.pid" #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; ProcessingMode Mode = InitProcessing;
/* Note: we rely on this to initialize as zeroes */ /* Note: we rely on this to initialize as zeroes */
...@@ -678,7 +691,7 @@ CreateLockFile(const char *filename, bool amPostmaster, ...@@ -678,7 +691,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
bool isDDLock, const char *refName) bool isDDLock, const char *refName)
{ {
int fd; int fd;
char buffer[MAXPGPATH * 2 + 256]; char buffer[MAXPGPATH * 3 + 256];
int ntries; int ntries;
int len; int len;
int encoded_pid; int encoded_pid;
...@@ -845,11 +858,10 @@ CreateLockFile(const char *filename, bool amPostmaster, ...@@ -845,11 +858,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
if (isDDLock) if (isDDLock)
{ {
char *ptr = buffer; char *ptr = buffer;
unsigned long id1, unsigned long id1, id2;
id2;
int lineno; int lineno;
for (lineno = 1; lineno <= 4; lineno++) for (lineno = 1; lineno <= LOCK_FILE_LINES - 1; lineno++)
{ {
if ((ptr = strchr(ptr, '\n')) == NULL) if ((ptr = strchr(ptr, '\n')) == NULL)
{ {
...@@ -893,9 +905,10 @@ CreateLockFile(const char *filename, bool amPostmaster, ...@@ -893,9 +905,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
/* /*
* Successfully created the file, now fill it. * 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), amPostmaster ? (int) my_pid : -((int) my_pid),
DataDir, PostPortNumber, UnixSocketDir); (long) MyStartTime, DataDir, PostPortNumber,
UnixSocketDir);
errno = 0; errno = 0;
if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
{ {
...@@ -1004,24 +1017,19 @@ TouchSocketLockFile(void) ...@@ -1004,24 +1017,19 @@ TouchSocketLockFile(void)
} }
} }
/* /*
* Append information about a shared memory segment to the data directory * Add lines to the data directory lock file. This erases all following
* lock file. * lines, but that is OK because lines are added in order.
*
* 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.)
*/ */
void void
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) AddToLockFile(int target_line, const char *str)
{ {
int fd; int fd;
int len; int len;
int lineno; int lineno;
char *ptr; char *ptr;
char buffer[MAXPGPATH * 2 + 256]; char buffer[MAXPGPATH * 3 + 256];
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
if (fd < 0) if (fd < 0)
...@@ -1048,7 +1056,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) ...@@ -1048,7 +1056,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
* Skip over first four lines (PID, pgdata, portnum, socketdir). * Skip over first four lines (PID, pgdata, portnum, socketdir).
*/ */
ptr = buffer; ptr = buffer;
for (lineno = 1; lineno <= 4; lineno++) for (lineno = 1; lineno < target_line; lineno++)
{ {
if ((ptr = strchr(ptr, '\n')) == NULL) if ((ptr = strchr(ptr, '\n')) == NULL)
{ {
...@@ -1059,11 +1067,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) ...@@ -1059,11 +1067,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
ptr++; ptr++;
} }
/* strlcat(buffer, str, sizeof(buffer));
* 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);
/* /*
* And rewrite the data. Since we write in a single kernel call, this * And rewrite the data. Since we write in a single kernel call, this
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <locale.h> #include <locale.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
...@@ -138,6 +139,7 @@ static void read_post_opts(void); ...@@ -138,6 +139,7 @@ static void read_post_opts(void);
static PGPing test_postmaster_connection(bool); static PGPing test_postmaster_connection(bool);
static bool postmaster_is_alive(pid_t pid); static bool postmaster_is_alive(pid_t pid);
static time_t start_time;
static char postopts_file[MAXPGPATH]; static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH]; static char pid_file[MAXPGPATH];
...@@ -404,13 +406,13 @@ static PGPing ...@@ -404,13 +406,13 @@ static PGPing
test_postmaster_connection(bool do_checkpoint) test_postmaster_connection(bool do_checkpoint)
{ {
int portnum = 0; int portnum = 0;
char socket_dir[MAXPGPATH]; char host_str[MAXPGPATH];
char connstr[MAXPGPATH + 256]; char connstr[MAXPGPATH + 256];
PGPing ret = PQPING_OK; /* assume success for wait == zero */ PGPing ret = PQPING_OK; /* assume success for wait == zero */
char **optlines; char **optlines;
int i; int i;
socket_dir[0] = '\0'; host_str[0] = '\0';
connstr[0] = '\0'; connstr[0] = '\0';
for (i = 0; i < wait_seconds; i++) for (i = 0; i < wait_seconds; i++)
...@@ -425,13 +427,14 @@ test_postmaster_connection(bool do_checkpoint) ...@@ -425,13 +427,14 @@ test_postmaster_connection(bool do_checkpoint)
* 0 lock file created but status not written * 0 lock file created but status not written
* 2 pre-9.1 server, shared memory not created * 2 pre-9.1 server, shared memory not created
* 3 pre-9.1 server, shared memory created * 3 pre-9.1 server, shared memory created
* 4 9.1+ server, shared memory not created * 5 9.1+ server, listen host not created
* 5 9.1+ server, shared memory 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 * 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 * 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 * written shmem key, so we fail. 9.1+ writes connection
* number and socket address in the file for us to use. * information in the file for us to use.
* (PG_VERSION could also have told us the major version.) * (PG_VERSION could also have told us the major version.)
*/ */
...@@ -439,7 +442,10 @@ test_postmaster_connection(bool do_checkpoint) ...@@ -439,7 +442,10 @@ test_postmaster_connection(bool do_checkpoint)
if ((optlines = readfile(pid_file)) != NULL && if ((optlines = readfile(pid_file)) != NULL &&
optlines[0] != NULL && optlines[0] != NULL &&
optlines[1] != 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? */ /* A 3-line file? */
if (optlines[3] == NULL) if (optlines[3] == NULL)
...@@ -459,31 +465,53 @@ test_postmaster_connection(bool do_checkpoint) ...@@ -459,31 +465,53 @@ test_postmaster_connection(bool do_checkpoint)
return PQPING_NO_ATTEMPT; return PQPING_NO_ATTEMPT;
} }
} }
else /* 9.1+ server */ else
{ {
portnum = atoi(optlines[2]); /*
* Easy check to see if we are looking at the right
/* Get socket directory, if specified. */ * data directory: Is the postmaster older than this
if (optlines[3][0] != '\n') * 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)
{ {
/* write_stderr(_("%s: this data directory is running an older postmaster\n"),
* While unix_socket_directory can accept relative progname);
* directories, libpq's host must have a leading slash return PQPING_NO_ATTEMPT;
* 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';
} }
}
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 * We need to set connect_timeout otherwise on Windows the
* Service Control Manager (SCM) will probably timeout first. * Service Control Manager (SCM) will probably timeout first.
...@@ -491,9 +519,9 @@ test_postmaster_connection(bool do_checkpoint) ...@@ -491,9 +519,9 @@ test_postmaster_connection(bool do_checkpoint)
snprintf(connstr, sizeof(connstr), snprintf(connstr, sizeof(connstr),
"dbname=postgres port=%d connect_timeout=5", portnum); "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), 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) ...@@ -1756,6 +1784,7 @@ main(int argc, char **argv)
progname = get_progname(argv[0]); progname = get_progname(argv[0]);
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl")); 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 * save argv[0] so do_start() can look for the postmaster if necessary. we
......
...@@ -348,11 +348,11 @@ extern PGDLLIMPORT bool process_shared_preload_libraries_in_progress; ...@@ -348,11 +348,11 @@ extern PGDLLIMPORT bool process_shared_preload_libraries_in_progress;
extern char *shared_preload_libraries_string; extern char *shared_preload_libraries_string;
extern char *local_preload_libraries_string; extern char *local_preload_libraries_string;
#define LOCK_FILE_LINES 7
extern void CreateDataDirLockFile(bool amPostmaster); extern void CreateDataDirLockFile(bool amPostmaster);
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster); extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
extern void TouchSocketLockFile(void); extern void TouchSocketLockFile(void);
extern void RecordSharedMemoryInLockFile(unsigned long id1, extern void AddToLockFile(int target_line, const char *str);
unsigned long id2);
extern void ValidatePgVersion(const char *path); extern void ValidatePgVersion(const char *path);
extern void process_shared_preload_libraries(void); extern void process_shared_preload_libraries(void);
extern void process_local_preload_libraries(void); extern void process_local_preload_libraries(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment