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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy