Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 075354a

Browse files
committed
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().
1 parent 4b1742a commit 075354a

File tree

3 files changed

+112
-158
lines changed

3 files changed

+112
-158
lines changed

doc/src/sgml/ref/pg_ctl-ref.sgml

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -348,21 +348,12 @@ PostgreSQL documentation
348348
<para>
349349
Wait for the startup or shutdown to complete.
350350
Waiting is the default option for shutdowns, but not startups.
351+
When waiting for startup, <command>pg_ctl</command> repeatedly
352+
attempts to connect to the server.
351353
When waiting for shutdown, <command>pg_ctl</command> waits for
352354
the server to remove its <acronym>PID</acronym> file.
353-
When waiting for startup, <command>pg_ctl</command> repeatedly
354-
attempts to connect to the server via <application>psql</>, and
355-
reports success when this is successful.
356-
<command>pg_ctl</command> will attempt to use the proper port for
357-
<application>psql</>. If the environment variable
358-
<envar>PGPORT</envar> exists, that is used. Otherwise,
359-
<command>pg_ctl</command> will see if a port has been set in the
360-
<filename>postgresql.conf</filename> file. If not, it will use the
361-
default port that <productname>PostgreSQL</productname> was compiled
362-
with (5432 by default).
363-
When waiting, <command>pg_ctl</command> will
364-
return an exit code based on the success of the startup
365-
or shutdown.
355+
<command>pg_ctl</command> returns an exit code based on the
356+
success of the startup or shutdown.
366357
</para>
367358
</listitem>
368359
</varlistentry>
@@ -442,28 +433,6 @@ PostgreSQL documentation
442433
</listitem>
443434
</varlistentry>
444435

445-
<varlistentry>
446-
<term><envar>PGHOST</envar></term>
447-
448-
<listitem>
449-
<para>
450-
Default host name or Unix-domain socket location for <xref
451-
linkend="app-psql"> (used when waiting for startup).
452-
</para>
453-
</listitem>
454-
</varlistentry>
455-
456-
<varlistentry>
457-
<term><envar>PGPORT</envar></term>
458-
459-
<listitem>
460-
<para>
461-
Default port number for <xref linkend="app-psql">
462-
(used when waiting for startup).
463-
</para>
464-
</listitem>
465-
</varlistentry>
466-
467436
</variablelist>
468437

469438
<para>
@@ -506,18 +475,6 @@ PostgreSQL documentation
506475
</listitem>
507476
</varlistentry>
508477

509-
<varlistentry>
510-
<term><filename>postgresql.conf</filename></term>
511-
512-
<listitem>
513-
<para>
514-
This file, located in the data directory, is parsed to find the
515-
proper port to use with <application>psql</application>
516-
when waiting for startup.
517-
</para>
518-
</listitem>
519-
</varlistentry>
520-
521478
</variablelist>
522479
</refsect1>
523480

src/backend/utils/init/miscinit.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "mb/pg_wchar.h"
3434
#include "miscadmin.h"
3535
#include "postmaster/autovacuum.h"
36+
#include "postmaster/postmaster.h"
3637
#include "storage/fd.h"
3738
#include "storage/ipc.h"
3839
#include "storage/pg_shmem.h"
@@ -658,7 +659,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
658659
bool isDDLock, const char *refName)
659660
{
660661
int fd;
661-
char buffer[MAXPGPATH + 100];
662+
char buffer[MAXPGPATH * 2 + 256];
662663
int ntries;
663664
int len;
664665
int encoded_pid;
@@ -868,9 +869,9 @@ CreateLockFile(const char *filename, bool amPostmaster,
868869
/*
869870
* Successfully created the file, now fill it.
870871
*/
871-
snprintf(buffer, sizeof(buffer), "%d\n%s\n",
872+
snprintf(buffer, sizeof(buffer), "%d\n%s\n%d\n%s\n",
872873
amPostmaster ? (int) my_pid : -((int) my_pid),
873-
DataDir);
874+
DataDir, PostPortNumber, UnixSocketDir);
874875
errno = 0;
875876
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
876877
{
@@ -994,8 +995,9 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
994995
{
995996
int fd;
996997
int len;
998+
int lineno;
997999
char *ptr;
998-
char buffer[BLCKSZ];
1000+
char buffer[MAXPGPATH * 2 + 256];
9991001

10001002
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
10011003
if (fd < 0)
@@ -1019,18 +1021,20 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
10191021
buffer[len] = '\0';
10201022

10211023
/*
1022-
* Skip over first two lines (PID and path).
1024+
* Skip over first four lines (PID, pgdata, portnum, socketdir).
10231025
*/
1024-
ptr = strchr(buffer, '\n');
1025-
if (ptr == NULL ||
1026-
(ptr = strchr(ptr + 1, '\n')) == NULL)
1026+
ptr = buffer;
1027+
for (lineno = 1; lineno <= 4; lineno++)
10271028
{
1028-
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
1029-
close(fd);
1030-
return;
1029+
if ((ptr = strchr(ptr, '\n')) == NULL)
1030+
{
1031+
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
1032+
close(fd);
1033+
return;
1034+
}
1035+
ptr++;
10311036
}
1032-
ptr++;
1033-
1037+
10341038
/*
10351039
* Append key information. Format to try to keep it the same length
10361040
* always (trailing junk won't hurt, but might confuse humans).

src/bin/pg_ctl/pg_ctl.c

Lines changed: 91 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ static bool postmaster_is_alive(pid_t pid);
141141

142142
static char postopts_file[MAXPGPATH];
143143
static char pid_file[MAXPGPATH];
144-
static char conf_file[MAXPGPATH];
145144
static char backup_file[MAXPGPATH];
146145
static char recovery_file[MAXPGPATH];
147146

@@ -404,113 +403,108 @@ start_postmaster(void)
404403
static PGPing
405404
test_postmaster_connection(bool do_checkpoint)
406405
{
406+
int portnum = 0;
407+
char socket_dir[MAXPGPATH];
408+
char connstr[MAXPGPATH + 256];
407409
PGPing ret = PQPING_OK; /* assume success for wait == zero */
410+
char **optlines;
408411
int i;
409-
char portstr[32];
410-
char *p;
411-
char *q;
412-
char connstr[128]; /* Should be way more than enough! */
413412

414-
portstr[0] = '\0';
415-
416-
/*
417-
* Look in post_opts for a -p switch.
418-
*
419-
* This parsing code is not amazingly bright; it could for instance get
420-
* fooled if ' -p' occurs within a quoted argument value. Given that few
421-
* people pass complicated settings in post_opts, it's probably good
422-
* enough.
423-
*/
424-
for (p = post_opts; *p;)
413+
socket_dir[0] = '\0';
414+
connstr[0] = '\0';
415+
416+
for (i = 0; i < wait_seconds; i++)
425417
{
426-
/* advance past whitespace */
427-
while (isspace((unsigned char) *p))
428-
p++;
429-
430-
if (strncmp(p, "-p", 2) == 0)
418+
/* Do we need a connection string? */
419+
if (connstr[0] == '\0')
431420
{
432-
p += 2;
433-
/* advance past any whitespace/quoting */
434-
while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
435-
p++;
436-
/* find end of value (not including any ending quote!) */
437-
q = p;
438-
while (*q &&
439-
!(isspace((unsigned char) *q) || *q == '\'' || *q == '"'))
440-
q++;
441-
/* and save the argument value */
442-
strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
443-
/* keep looking, maybe there is another -p */
444-
p = q;
445-
}
446-
/* Advance to next whitespace */
447-
while (*p && !isspace((unsigned char) *p))
448-
p++;
449-
}
421+
/*
422+
* The number of lines in postmaster.pid tells us several things:
423+
*
424+
* # of lines
425+
* 0 lock file created but status not written
426+
* 2 pre-9.1 server, shared memory not created
427+
* 3 pre-9.1 server, shared memory created
428+
* 4 9.1+ server, shared memory not created
429+
* 5 9.1+ server, shared memory created
430+
*
431+
* For pre-9.1 Unix servers, we grab the port number from the
432+
* shmem key (first value on line 3). Pre-9.1 Win32 has no
433+
* written shmem key, so we fail. 9.1+ writes both the port
434+
* number and socket address in the file for us to use.
435+
* (PG_VERSION could also have told us the major version.)
436+
*/
437+
438+
/* Try to read a completed postmaster.pid file */
439+
if ((optlines = readfile(pid_file)) != NULL &&
440+
optlines[0] != NULL &&
441+
optlines[1] != NULL &&
442+
optlines[2] != NULL)
443+
{
444+
/* A 3-line file? */
445+
if (optlines[3] == NULL)
446+
{
447+
/*
448+
* Pre-9.1: on Unix, we get the port number by
449+
* deriving it from the shmem key (the first number on
450+
* on the line); see
451+
* miscinit.c::RecordSharedMemoryInLockFile().
452+
*/
453+
portnum = atoi(optlines[2]) / 1000;
454+
/* Win32 does not give us a shmem key, so we fail. */
455+
if (portnum == 0)
456+
{
457+
write_stderr(_("%s: -w option is not supported on this platform\nwhen connecting to a pre-9.1 server\n"),
458+
progname);
459+
return PQPING_NO_ATTEMPT;
460+
}
461+
}
462+
else /* 9.1+ server */
463+
{
464+
portnum = atoi(optlines[2]);
465+
466+
/* Get socket directory, if specified. */
467+
if (optlines[3][0] != '\n')
468+
{
469+
/*
470+
* While unix_socket_directory can accept relative
471+
* directories, libpq's host must have a leading slash
472+
* to indicate a socket directory.
473+
*/
474+
if (optlines[3][0] != '/')
475+
{
476+
write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
477+
progname);
478+
return PQPING_NO_ATTEMPT;
479+
}
480+
strlcpy(socket_dir, optlines[3], MAXPGPATH);
481+
/* remove newline */
482+
if (strchr(socket_dir, '\n') != NULL)
483+
*strchr(socket_dir, '\n') = '\0';
484+
}
485+
}
450486

451-
/*
452-
* Search config file for a 'port' option.
453-
*
454-
* This parsing code isn't amazingly bright either, but it should be okay
455-
* for valid port settings.
456-
*/
457-
if (!portstr[0])
458-
{
459-
char **optlines;
487+
/*
488+
* We need to set connect_timeout otherwise on Windows the
489+
* Service Control Manager (SCM) will probably timeout first.
490+
*/
491+
snprintf(connstr, sizeof(connstr),
492+
"dbname=postgres port=%d connect_timeout=5", portnum);
460493

461-
optlines = readfile(conf_file);
462-
if (optlines != NULL)
463-
{
464-
for (; *optlines != NULL; optlines++)
465-
{
466-
p = *optlines;
467-
468-
while (isspace((unsigned char) *p))
469-
p++;
470-
if (strncmp(p, "port", 4) != 0)
471-
continue;
472-
p += 4;
473-
while (isspace((unsigned char) *p))
474-
p++;
475-
if (*p != '=')
476-
continue;
477-
p++;
478-
/* advance past any whitespace/quoting */
479-
while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
480-
p++;
481-
/* find end of value (not including any ending quote/comment!) */
482-
q = p;
483-
while (*q &&
484-
!(isspace((unsigned char) *q) ||
485-
*q == '\'' || *q == '"' || *q == '#'))
486-
q++;
487-
/* and save the argument value */
488-
strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
489-
/* keep looking, maybe there is another */
494+
if (socket_dir[0] != '\0')
495+
snprintf(connstr + strlen(connstr), sizeof(connstr) - strlen(connstr),
496+
" host='%s'", socket_dir);
490497
}
491498
}
492-
}
493499

494-
/* Check environment */
495-
if (!portstr[0] && getenv("PGPORT") != NULL)
496-
strlcpy(portstr, getenv("PGPORT"), sizeof(portstr));
497-
498-
/* Else use compiled-in default */
499-
if (!portstr[0])
500-
snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
501-
502-
/*
503-
* We need to set a connect timeout otherwise on Windows the SCM will
504-
* probably timeout first
505-
*/
506-
snprintf(connstr, sizeof(connstr),
507-
"dbname=postgres port=%s connect_timeout=5", portstr);
500+
/* If we have a connection string, ping the server */
501+
if (connstr[0] != '\0')
502+
{
503+
ret = PQping(connstr);
504+
if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
505+
break;
506+
}
508507

509-
for (i = 0; i < wait_seconds; i++)
510-
{
511-
ret = PQping(connstr);
512-
if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
513-
break;
514508
/* No response, or startup still in process; wait */
515509
#if defined(WIN32)
516510
if (do_checkpoint)
@@ -2009,7 +2003,6 @@ main(int argc, char **argv)
20092003
{
20102004
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
20112005
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
2012-
snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);
20132006
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
20142007
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
20152008
}

0 commit comments

Comments
 (0)