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  <br...@momjian.us>        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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to