On Mon, Aug 13, 2012 at 12:46:43PM +0200, Magnus Hagander wrote:
> On Mon, Aug 13, 2012 at 4:34 AM, Tom Lane <t...@sss.pgh.pa.us> wrote:
> > I've been experimenting with moving the Unix socket directory to
> > /var/run/postgresql for the Fedora distribution (don't ask :-().
> > It's mostly working, but I found out yet another way that pg_upgrade
> > can crash and burn: it doesn't consider the possibility that the
> > old or new postmaster is compiled with a different default
> > unix_socket_directory than what is compiled into the libpq it's using
> > or that pg_dump is using.
> >
> > This is another hazard that we could forget about if we had some way for
> > pg_upgrade to run standalone backends instead of starting a postmaster.
> 
> Yeah, that would be nice.
> 
> 
> > But in the meantime, I suggest it'd be a good idea for pg_upgrade to
> > explicitly set unix_socket_directory (or unix_socket_directories in
> > HEAD) when starting the postmasters, and also explicitly set PGHOST
> > to ensure that the client-side code plays along.
> 
> That sounds like a good idea for other reasons as well - manual
> connections attempting to get in during an upgrade will just fail with
> a "no connection" error, which makes sense...
> 
> So, +1.

OK, I looked this over, and I have a patch, attached.

Because we are already playing with socket directories, this patch creates
the socket files in the current directory for upgrades and non-live
checks, but not live checks.  This eliminates the "someone accidentally
connects" problem, at least on Unix, plus we are using port 50432
already.  This also turns off TCP connections for unix domain socket
systems.

For "live check" operation, you are checking a running server, so
assuming the socket is in the current directory is not going to work.
What the code does is to read the 5th line from the running server's
postmaster.pid file, which has the socket directory in PG >= 9.1.  For
pre-9.1, pg_upgrade uses the compiled-in defaults for socket directory.
If the defaults are different between the two servers, the new binaries,
e.g. pg_dump, will not work.  The fix is for the user to set pg_upgrade
-O to match the old socket directory, and set PGHOST before running
pg_upgrade.  I could not find a good way to generate a proper error
message because we are blind to the socket directory in pre-9.1. 
Frankly, this is a problem if the old pre-9.1 server is running in a
user-configured socket directory too, so a documentation addition seems
right here.

So, in summary, this patch moves the socket directory to the current
directory all but live check operation, and handles different socket
directories for old cluster >= 9.1.  I have added a documentation
mention of how to make this work for for pre-9.1 old servers.

Thus completes another "surgery on a moving train" that is pg_upgrade
development.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + It's impossible for everything to be true. +
diff --git a/contrib/pg_upgrade/option.c b/contrib/pg_upgrade/option.c
new file mode 100644
index 94bce50..8b35d8f
*** a/contrib/pg_upgrade/option.c
--- b/contrib/pg_upgrade/option.c
*************** adjust_data_dir(ClusterInfo *cluster)
*** 376,378 ****
--- 376,431 ----
  
  	check_ok();
  }
+ 
+ 
+ #if HAVE_UNIX_SOCKETS
+ /*
+  * set_sockdir_and_pghost
+  *
+  * Set the socket directory to either the configured location (live check)
+  * or the current directory.
+  */
+ void
+ set_sockdir_and_pghost(bool live_check)
+ {
+ 	if (!live_check)
+ 	{
+ 		/* Use the current directory for the socket */
+ 		if (!getcwd(os_info.sockdir, MAXPGPATH))
+ 			pg_log(PG_FATAL, "cannot find current directory\n");
+ 	}
+ 	else
+ 	{
+ 		/*
+ 		 *	If we are doing a live check, we will use the old cluster's Unix
+ 		 *	domain socket directory so we can connect to the live server.
+ 		 */
+ 
+ 		/* sockdir added to the 5th line of postmaster.pid in PG 9.1 */
+ 		if (GET_MAJOR_VERSION(old_cluster.major_version) >= 901)
+ 		{
+ 			char		filename[MAXPGPATH];
+ 			FILE		*fp;
+ 			int			i;
+ 
+ 			snprintf(filename, sizeof(filename), "%s/postmaster.pid", old_cluster.pgdata);
+ 			if ((fp = fopen(filename, "r")) == NULL)
+ 				pg_log(PG_FATAL, "Could not get socket directory of the old server\n");
+ 
+ 			for (i = 0; i < 5; i++)
+ 				if (fgets(os_info.sockdir, sizeof(os_info.sockdir), fp) == NULL)
+ 					pg_log(PG_FATAL, "Could not get socket directory of the old server\n");
+ 			fclose(fp);
+ 		}
+ 		else
+ 			return;		/* Can't get live sockdir, so use the default. */
+ 
+ 		/* Remove trailing newline */
+ 		if (strchr(os_info.sockdir, '\n') != NULL)
+ 			*strchr(os_info.sockdir, '\n') = '\0';
+ 	}
+ 
+ 	/* For client communication */
+ 	pg_putenv("PGHOST", os_info.sockdir);
+ }
+ #endif
diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c
new file mode 100644
index c47c8bb..8cad5c3
*** a/contrib/pg_upgrade/pg_upgrade.c
--- b/contrib/pg_upgrade/pg_upgrade.c
*************** main(int argc, char **argv)
*** 88,93 ****
--- 88,97 ----
  	check_cluster_versions();
  	check_cluster_compatibility(live_check);
  
+ #if HAVE_UNIX_SOCKETS
+ 	set_sockdir_and_pghost(live_check);
+ #endif
+ 
  	check_old_cluster(live_check, &sequence_script_file_name);
  
  
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
new file mode 100644
index fa4c6c0..a712e21
*** a/contrib/pg_upgrade/pg_upgrade.h
--- b/contrib/pg_upgrade/pg_upgrade.h
*************** typedef struct
*** 267,272 ****
--- 267,275 ----
  	const char *progname;		/* complete pathname for this program */
  	char	   *exec_path;		/* full path to my executable */
  	char	   *user;			/* username for clusters */
+ #if HAVE_UNIX_SOCKETS
+ 	char		sockdir[NAMEDATALEN];	/* directory for Unix Domain socket */
+ #endif
  	char	  **tablespaces;	/* tablespaces */
  	int			num_tablespaces;
  	char	  **libraries;		/* loadable libraries */
*************** void print_maps(FileNameMap *maps, int n
*** 387,392 ****
--- 390,398 ----
  
  void		parseCommandLine(int argc, char *argv[]);
  void		adjust_data_dir(ClusterInfo *cluster);
+ #if HAVE_UNIX_SOCKETS
+ void		set_sockdir_and_pghost(bool live_check);
+ #endif
  
  /* relfilenode.c */
  
diff --git a/contrib/pg_upgrade/server.c b/contrib/pg_upgrade/server.c
new file mode 100644
index 1fb0d6c..c042fb4
*** a/contrib/pg_upgrade/server.c
--- b/contrib/pg_upgrade/server.c
*************** start_postmaster(ClusterInfo *cluster)
*** 144,149 ****
--- 144,150 ----
  	PGconn	   *conn;
  	bool		exit_hook_registered = false;
  	bool		pg_ctl_return = false;
+ 	char		socket_string[MAXPGPATH + 100];
  
  	if (!exit_hook_registered)
  	{
*************** start_postmaster(ClusterInfo *cluster)
*** 151,156 ****
--- 152,178 ----
  		exit_hook_registered = true;
  	}
  
+ 	socket_string[0] = '\0';
+ 
+ #ifdef HAVE_UNIX_SOCKETS
+ 	/*
+ 	 *	Report the Unix domain socket directory location to the postmaster.
+ 	 */
+ 
+ #define LISTEN_STR	" -c listen_addresses=''"
+ 
+ 	/* Have a sockdir to use? */
+ 	if (strlen(os_info.sockdir) != 0)
+ 		snprintf(socket_string, sizeof(socket_string) - strlen(LISTEN_STR),
+ 			" -c %s='%s'",
+ 			(GET_MAJOR_VERSION(cluster->major_version) < 903) ?
+ 				"unix_socket_directory" : "unix_socket_directories",
+ 			os_info.sockdir);
+ 	
+ 	/* prevent TCP/IP connections */
+ 	strcat(socket_string, LISTEN_STR);
+ #endif
+ 
  	/*
  	 * Using autovacuum=off disables cleanup vacuum and analyze, but freeze
  	 * vacuums can still happen, so we set autovacuum_freeze_max_age to its
*************** start_postmaster(ClusterInfo *cluster)
*** 159,170 ****
  	 * not touch them.
  	 */
  	snprintf(cmd, sizeof(cmd),
! 			 "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d %s %s\" start",
  		  cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
  			 (cluster->controldata.cat_ver >=
  			  BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
  			 "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
! 			 cluster->pgopts ? cluster->pgopts : "");
  
  	/*
  	 * Don't throw an error right away, let connecting throw the error because
--- 181,192 ----
  	 * not touch them.
  	 */
  	snprintf(cmd, sizeof(cmd),
! 			 "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d %s %s%s\" start",
  		  cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port,
  			 (cluster->controldata.cat_ver >=
  			  BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" :
  			 "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000",
! 			 cluster->pgopts ? cluster->pgopts : "", socket_string);
  
  	/*
  	 * Don't throw an error right away, let connecting throw the error because
diff --git a/doc/src/sgml/pgupgrade.sgml b/doc/src/sgml/pgupgrade.sgml
new file mode 100644
index b62aba2..b621911
*** a/doc/src/sgml/pgupgrade.sgml
--- b/doc/src/sgml/pgupgrade.sgml
*************** psql --username postgres --file script.s
*** 520,525 ****
--- 520,532 ----
    </para>
  
    <para>
+    If running check on an old pre-9.1 Unix-like running server, and the
+    old and new servers use different Unix-domain socket directories,
+    use the <option>-O</> option so the new server uses the same socket
+    directory as the old server, and set <envar>PGHOST</> similarly.
+   </para>
+ 
+   <para>
     A Log-Shipping Standby Server (<xref linkend="warm-standby">) cannot
     be upgraded because the server must allow writes.  The simplest way
     is to upgrade the primary and use rsync to rebuild the standbys.
-- 
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