mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
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().
This commit is contained in:
@ -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
|
|||||||
</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
|
|||||||
</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 @@
|
|||||||
#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,
|
|||||||
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,
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
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,18 +1021,20 @@ 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)
|
|
||||||
{
|
{
|
||||||
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
|
if ((ptr = strchr(ptr, '\n')) == NULL)
|
||||||
close(fd);
|
{
|
||||||
return;
|
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
|
||||||
|
close(fd);
|
||||||
|
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
|
||||||
* always (trailing junk won't hurt, but might confuse humans).
|
* always (trailing junk won't hurt, but might confuse humans).
|
||||||
|
@ -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)
|
|||||||
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';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look in post_opts for a -p switch.
|
|
||||||
*
|
|
||||||
* This parsing code is not amazingly bright; it could for instance get
|
|
||||||
* fooled if ' -p' occurs within a quoted argument value. Given that few
|
|
||||||
* people pass complicated settings in post_opts, it's probably good
|
|
||||||
* enough.
|
|
||||||
*/
|
|
||||||
for (p = post_opts; *p;)
|
|
||||||
{
|
|
||||||
/* advance past whitespace */
|
|
||||||
while (isspace((unsigned char) *p))
|
|
||||||
p++;
|
|
||||||
|
|
||||||
if (strncmp(p, "-p", 2) == 0)
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
*
|
|
||||||
* This parsing code isn't amazingly bright either, but it should be okay
|
|
||||||
* for valid port settings.
|
|
||||||
*/
|
|
||||||
if (!portstr[0])
|
|
||||||
{
|
|
||||||
char **optlines;
|
|
||||||
|
|
||||||
optlines = readfile(conf_file);
|
|
||||||
if (optlines != NULL)
|
|
||||||
{
|
|
||||||
for (; *optlines != NULL; optlines++)
|
|
||||||
{
|
|
||||||
p = *optlines;
|
|
||||||
|
|
||||||
while (isspace((unsigned char) *p))
|
|
||||||
p++;
|
|
||||||
if (strncmp(p, "port", 4) != 0)
|
|
||||||
continue;
|
|
||||||
p += 4;
|
|
||||||
while (isspace((unsigned char) *p))
|
|
||||||
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
|
|
||||||
* probably timeout first
|
|
||||||
*/
|
|
||||||
snprintf(connstr, sizeof(connstr),
|
|
||||||
"dbname=postgres port=%s connect_timeout=5", portstr);
|
|
||||||
|
|
||||||
|
socket_dir[0] = '\0';
|
||||||
|
connstr[0] = '\0';
|
||||||
|
|
||||||
for (i = 0; i < wait_seconds; i++)
|
for (i = 0; i < wait_seconds; i++)
|
||||||
{
|
{
|
||||||
ret = PQping(connstr);
|
/* Do we need a connection string? */
|
||||||
if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
|
if (connstr[0] == '\0')
|
||||||
break;
|
{
|
||||||
|
/*
|
||||||
|
* The number of lines in postmaster.pid tells us several things:
|
||||||
|
*
|
||||||
|
* # of lines
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Pre-9.1: on Unix, we get the port number by
|
||||||
|
* deriving it from the shmem key (the first number on
|
||||||
|
* on the line); see
|
||||||
|
* miscinit.c::RecordSharedMemoryInLockFile().
|
||||||
|
*/
|
||||||
|
portnum = atoi(optlines[2]) / 1000;
|
||||||
|
/* Win32 does not give us a shmem key, so we fail. */
|
||||||
|
if (portnum == 0)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
|
||||||
|
/* Get socket directory, if specified. */
|
||||||
|
if (optlines[3][0] != '\n')
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to set connect_timeout otherwise on Windows the
|
||||||
|
* Service Control Manager (SCM) will probably timeout first.
|
||||||
|
*/
|
||||||
|
snprintf(connstr, sizeof(connstr),
|
||||||
|
"dbname=postgres port=%d connect_timeout=5", portnum);
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
|
||||||
|
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)
|
|||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user