Commit 075354ad authored by Bruce Momjian's avatar Bruce Momjian

Improve "pg_ctl -w start" server detection by writing the postmaster

port and socket directory into postmaster.pid, and have pg_ctl read from
that file, for use by PQping().
parent 4b1742a1
...@@ -348,21 +348,12 @@ PostgreSQL documentation ...@@ -348,21 +348,12 @@ PostgreSQL documentation
<para> <para>
Wait for the startup or shutdown to complete. Wait for the startup or shutdown to complete.
Waiting is the default option for shutdowns, but not startups. Waiting is the default option for shutdowns, but not startups.
When waiting for startup, <command>pg_ctl</command> repeatedly
attempts to connect to the server.
When waiting for shutdown, <command>pg_ctl</command> waits for When waiting for shutdown, <command>pg_ctl</command> waits for
the server to remove its <acronym>PID</acronym> file. the server to remove its <acronym>PID</acronym> file.
When waiting for startup, <command>pg_ctl</command> repeatedly <command>pg_ctl</command> returns an exit code based on the
attempts to connect to the server via <application>psql</>, and success of the startup or shutdown.
reports success when this is successful.
<command>pg_ctl</command> will attempt to use the proper port for
<application>psql</>. If the environment variable
<envar>PGPORT</envar> exists, that is used. Otherwise,
<command>pg_ctl</command> will see if a port has been set in the
<filename>postgresql.conf</filename> file. If not, it will use the
default port that <productname>PostgreSQL</productname> was compiled
with (5432 by default).
When waiting, <command>pg_ctl</command> will
return an exit code based on the success of the startup
or shutdown.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -442,28 +433,6 @@ PostgreSQL documentation ...@@ -442,28 +433,6 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><envar>PGHOST</envar></term>
<listitem>
<para>
Default host name or Unix-domain socket location for <xref
linkend="app-psql"> (used when waiting for startup).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><envar>PGPORT</envar></term>
<listitem>
<para>
Default port number for <xref linkend="app-psql">
(used when waiting for startup).
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<para> <para>
...@@ -506,18 +475,6 @@ PostgreSQL documentation ...@@ -506,18 +475,6 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><filename>postgresql.conf</filename></term>
<listitem>
<para>
This file, located in the data directory, is parsed to find the
proper port to use with <application>psql</application>
when waiting for startup.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "postmaster/autovacuum.h" #include "postmaster/autovacuum.h"
#include "postmaster/postmaster.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/pg_shmem.h" #include "storage/pg_shmem.h"
...@@ -658,7 +659,7 @@ CreateLockFile(const char *filename, bool amPostmaster, ...@@ -658,7 +659,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
bool isDDLock, const char *refName) bool isDDLock, const char *refName)
{ {
int fd; int fd;
char buffer[MAXPGPATH + 100]; char buffer[MAXPGPATH * 2 + 256];
int ntries; int ntries;
int len; int len;
int encoded_pid; int encoded_pid;
...@@ -868,9 +869,9 @@ CreateLockFile(const char *filename, bool amPostmaster, ...@@ -868,9 +869,9 @@ 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", snprintf(buffer, sizeof(buffer), "%d\n%s\n%d\n%s\n",
amPostmaster ? (int) my_pid : -((int) my_pid), amPostmaster ? (int) my_pid : -((int) my_pid),
DataDir); DataDir, PostPortNumber, UnixSocketDir);
errno = 0; errno = 0;
if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
{ {
...@@ -994,8 +995,9 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) ...@@ -994,8 +995,9 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
{ {
int fd; int fd;
int len; int len;
int lineno;
char *ptr; char *ptr;
char buffer[BLCKSZ]; char buffer[MAXPGPATH * 2 + 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)
...@@ -1019,17 +1021,19 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) ...@@ -1019,17 +1021,19 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
buffer[len] = '\0'; buffer[len] = '\0';
/* /*
* Skip over first two lines (PID and path). * Skip over first four lines (PID, pgdata, portnum, socketdir).
*/ */
ptr = strchr(buffer, '\n'); ptr = buffer;
if (ptr == NULL || for (lineno = 1; lineno <= 4; lineno++)
(ptr = strchr(ptr + 1, '\n')) == NULL) {
if ((ptr = strchr(ptr, '\n')) == NULL)
{ {
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE); elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
close(fd); close(fd);
return; return;
} }
ptr++; ptr++;
}
/* /*
* Append key information. Format to try to keep it the same length * Append key information. Format to try to keep it the same length
......
...@@ -141,7 +141,6 @@ static bool postmaster_is_alive(pid_t pid); ...@@ -141,7 +141,6 @@ static bool postmaster_is_alive(pid_t pid);
static char postopts_file[MAXPGPATH]; static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH]; static char pid_file[MAXPGPATH];
static char conf_file[MAXPGPATH];
static char backup_file[MAXPGPATH]; static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH]; static char recovery_file[MAXPGPATH];
...@@ -404,113 +403,108 @@ start_postmaster(void) ...@@ -404,113 +403,108 @@ start_postmaster(void)
static PGPing static PGPing
test_postmaster_connection(bool do_checkpoint) test_postmaster_connection(bool do_checkpoint)
{ {
int portnum = 0;
char socket_dir[MAXPGPATH];
char connstr[MAXPGPATH + 256];
PGPing ret = PQPING_OK; /* assume success for wait == zero */ PGPing ret = PQPING_OK; /* assume success for wait == zero */
char **optlines;
int i; int i;
char portstr[32];
char *p;
char *q;
char connstr[128]; /* Should be way more than enough! */
portstr[0] = '\0'; socket_dir[0] = '\0';
connstr[0] = '\0';
for (i = 0; i < wait_seconds; i++)
{
/* Do we need a connection string? */
if (connstr[0] == '\0')
{
/* /*
* Look in post_opts for a -p switch. * The number of lines in postmaster.pid tells us several things:
* *
* This parsing code is not amazingly bright; it could for instance get * # of lines
* fooled if ' -p' occurs within a quoted argument value. Given that few * 0 lock file created but status not written
* people pass complicated settings in post_opts, it's probably good * 2 pre-9.1 server, shared memory not created
* enough. * 3 pre-9.1 server, shared memory created
* 4 9.1+ server, shared memory not created
* 5 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.
* (PG_VERSION could also have told us the major version.)
*/ */
for (p = post_opts; *p;)
{
/* advance past whitespace */
while (isspace((unsigned char) *p))
p++;
if (strncmp(p, "-p", 2) == 0) /* Try to read a completed postmaster.pid file */
if ((optlines = readfile(pid_file)) != NULL &&
optlines[0] != NULL &&
optlines[1] != NULL &&
optlines[2] != NULL)
{
/* A 3-line file? */
if (optlines[3] == NULL)
{ {
p += 2;
/* advance past any whitespace/quoting */
while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
p++;
/* find end of value (not including any ending quote!) */
q = p;
while (*q &&
!(isspace((unsigned char) *q) || *q == '\'' || *q == '"'))
q++;
/* and save the argument value */
strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
/* keep looking, maybe there is another -p */
p = q;
}
/* Advance to next whitespace */
while (*p && !isspace((unsigned char) *p))
p++;
}
/* /*
* Search config file for a 'port' option. * Pre-9.1: on Unix, we get the port number by
* * deriving it from the shmem key (the first number on
* This parsing code isn't amazingly bright either, but it should be okay * on the line); see
* for valid port settings. * miscinit.c::RecordSharedMemoryInLockFile().
*/ */
if (!portstr[0]) portnum = atoi(optlines[2]) / 1000;
/* Win32 does not give us a shmem key, so we fail. */
if (portnum == 0)
{ {
char **optlines; write_stderr(_("%s: -w option is not supported on this platform\nwhen connecting to a pre-9.1 server\n"),
progname);
return PQPING_NO_ATTEMPT;
}
}
else /* 9.1+ server */
{
portnum = atoi(optlines[2]);
optlines = readfile(conf_file); /* Get socket directory, if specified. */
if (optlines != NULL) if (optlines[3][0] != '\n')
{ {
for (; *optlines != NULL; optlines++) /*
* 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] != '/')
{ {
p = *optlines; write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
progname);
while (isspace((unsigned char) *p)) return PQPING_NO_ATTEMPT;
p++; }
if (strncmp(p, "port", 4) != 0) strlcpy(socket_dir, optlines[3], MAXPGPATH);
continue; /* remove newline */
p += 4; if (strchr(socket_dir, '\n') != NULL)
while (isspace((unsigned char) *p)) *strchr(socket_dir, '\n') = '\0';
p++; }
if (*p != '=') }
continue;
p++;
/* advance past any whitespace/quoting */
while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
p++;
/* find end of value (not including any ending quote/comment!) */
q = p;
while (*q &&
!(isspace((unsigned char) *q) ||
*q == '\'' || *q == '"' || *q == '#'))
q++;
/* and save the argument value */
strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
/* keep looking, maybe there is another */
}
}
}
/* Check environment */
if (!portstr[0] && getenv("PGPORT") != NULL)
strlcpy(portstr, getenv("PGPORT"), sizeof(portstr));
/* Else use compiled-in default */
if (!portstr[0])
snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
/* /*
* We need to set a connect timeout otherwise on Windows the SCM will * We need to set connect_timeout otherwise on Windows the
* probably timeout first * Service Control Manager (SCM) will probably timeout first.
*/ */
snprintf(connstr, sizeof(connstr), snprintf(connstr, sizeof(connstr),
"dbname=postgres port=%s connect_timeout=5", portstr); "dbname=postgres port=%d connect_timeout=5", portnum);
for (i = 0; i < wait_seconds; i++) if (socket_dir[0] != '\0')
snprintf(connstr + strlen(connstr), sizeof(connstr) - strlen(connstr),
" host='%s'", socket_dir);
}
}
/* If we have a connection string, ping the server */
if (connstr[0] != '\0')
{ {
ret = PQping(connstr); ret = PQping(connstr);
if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT) if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
break; break;
}
/* No response, or startup still in process; wait */ /* No response, or startup still in process; wait */
#if defined(WIN32) #if defined(WIN32)
if (do_checkpoint) if (do_checkpoint)
...@@ -2009,7 +2003,6 @@ main(int argc, char **argv) ...@@ -2009,7 +2003,6 @@ main(int argc, char **argv)
{ {
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data); snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data); snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data); snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data); snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
} }
......
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