Tom Lane wrote:
> Actually, if we're going to do this at all, we should do
>
> pid
> datadir
> port
> socketdir
> ... here be dragons ...
>
> so that pg_ctl doesn't have to assume the server is running with a
> default value of unix_socket_dir. Not sure what to put in the fourth
> line on Windows though ... maybe just leave it empty?
OK, here is a patch that adds the port number and optionally socket
directory location to postmaster.pid, and modifies pg_ctl to use that
information. I throw an error on using Win32 with pre-9.1 servers
because we can't get the port number from that file.
This removes some crufty code from pg_ctl and removes dependency on
serveral user-configurable settings that we added as a work-around.
This will allow pg_ctl -w to work more reliabily than it did in the
past.
--
Bruce Momjian <[email protected]> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 2c01e12..c526e8e 100644
*** /tmp/pgrevert.8079/5dqQCd_pg_ctl-ref.sgml Wed Dec 22 10:10:23 2010
--- doc/src/sgml/ref/pg_ctl-ref.sgml Wed Dec 22 10:06:33 2010
*************** PostgreSQL documentation
*** 348,368 ****
<para>
Wait for the startup or shutdown to complete.
Waiting is the default option for shutdowns, but not startups.
When waiting for shutdown, <command>pg_ctl</command> waits for
the server to remove its <acronym>PID</acronym> file.
! When waiting for startup, <command>pg_ctl</command> repeatedly
! attempts to connect to the server via <application>psql</>, and
! 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>
</listitem>
</varlistentry>
--- 348,359 ----
<para>
Wait for the startup or shutdown to complete.
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
the server to remove its <acronym>PID</acronym> file.
! <command>pg_ctl</command> returns an exit code based on the
! success of the startup or shutdown.
</para>
</listitem>
</varlistentry>
*************** PostgreSQL documentation
*** 442,469 ****
</listitem>
</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>
<para>
--- 433,438 ----
*************** PostgreSQL documentation
*** 506,523 ****
</listitem>
</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>
</refsect1>
--- 475,480 ----
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 14ed914..deb2d58 100644
*** /tmp/pgrevert.8079/PNev2b_miscinit.c Wed Dec 22 10:10:23 2010
--- src/backend/utils/init/miscinit.c Wed Dec 22 10:06:33 2010
***************
*** 33,38 ****
--- 33,39 ----
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
+ #include "postmaster/postmaster.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
*************** CreateLockFile(const char *filename, boo
*** 658,664 ****
bool isDDLock, const char *refName)
{
int fd;
! char buffer[MAXPGPATH + 100];
int ntries;
int len;
int encoded_pid;
--- 659,665 ----
bool isDDLock, const char *refName)
{
int fd;
! char buffer[MAXPGPATH * 2 + 256];
int ntries;
int len;
int encoded_pid;
*************** CreateLockFile(const char *filename, boo
*** 868,876 ****
/*
* Successfully created the file, now fill it.
*/
! snprintf(buffer, sizeof(buffer), "%d\n%s\n",
amPostmaster ? (int) my_pid : -((int) my_pid),
! DataDir);
errno = 0;
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
{
--- 869,877 ----
/*
* Successfully created the file, now fill it.
*/
! snprintf(buffer, sizeof(buffer), "%d\n%s\n%d\n%s\n",
amPostmaster ? (int) my_pid : -((int) my_pid),
! DataDir, PostPortNumber, UnixSocketDir);
errno = 0;
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
{
*************** RecordSharedMemoryInLockFile(unsigned lo
*** 994,1001 ****
{
int fd;
int len;
char *ptr;
! char buffer[BLCKSZ];
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
if (fd < 0)
--- 995,1003 ----
{
int fd;
int len;
+ int lineno;
char *ptr;
! char buffer[MAXPGPATH * 2 + 256];
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
if (fd < 0)
*************** RecordSharedMemoryInLockFile(unsigned lo
*** 1019,1036 ****
buffer[len] = '\0';
/*
! * Skip over first two lines (PID and path).
*/
! ptr = strchr(buffer, '\n');
! if (ptr == NULL ||
! (ptr = strchr(ptr + 1, '\n')) == NULL)
{
! elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
! close(fd);
! return;
}
! ptr++;
!
/*
* Append key information. Format to try to keep it the same length
* always (trailing junk won't hurt, but might confuse humans).
--- 1021,1040 ----
buffer[len] = '\0';
/*
! * Skip over first four lines (PID, pgdata, portnum, socketdir).
*/
! ptr = buffer;
! for (lineno = 1; lineno <= 4; lineno++)
{
! if ((ptr = strchr(ptr, '\n')) == NULL)
! {
! elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
! close(fd);
! return;
! }
! ptr++;
}
!
/*
* Append key information. Format to try to keep it the same length
* always (trailing junk won't hurt, but might confuse humans).
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index c5f855e..b91612a 100644
*** /tmp/pgrevert.8079/9n6jMb_pg_ctl.c Wed Dec 22 10:10:23 2010
--- src/bin/pg_ctl/pg_ctl.c Wed Dec 22 10:10:09 2010
*************** static bool postmaster_is_alive(pid_t pi
*** 141,147 ****
static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH];
- static char conf_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH];
--- 141,146 ----
*************** start_postmaster(void)
*** 404,516 ****
static PGPing
test_postmaster_connection(bool do_checkpoint)
{
PGPing ret = PQPING_OK; /* assume success for wait == zero */
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);
- for (i = 0; i < wait_seconds; i++)
- {
- ret = PQping(connstr);
- if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
- break;
/* No response, or startup still in process; wait */
#if defined(WIN32)
if (do_checkpoint)
--- 403,509 ----
static PGPing
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 */
+ char **optlines;
int i;
! socket_dir[0] = '\0';
! connstr[0] = '\0';
!
! for (i = 0; i < wait_seconds; i++)
{
! /* Do we need a connection string? */
! if (connstr[0] == '\0')
{
! /*
! * 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.
! */
!
! /* 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 */
#if defined(WIN32)
if (do_checkpoint)
*************** main(int argc, char **argv)
*** 2009,2015 ****
{
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", 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(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
}
--- 2002,2007 ----
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers