3232#include "common/username.h"
3333#include "getopt_long.h"
3434#include "lib/stringinfo.h"
35+ #include "libpq-fe.h"
3536#include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
3637#include "pg_config_paths.h"
3738#include "pg_regress.h"
@@ -75,6 +76,12 @@ const char *pretty_diff_opts = "-w -U3";
7576 */
7677#define TESTNAME_WIDTH 36
7778
79+ /*
80+ * The number times per second that pg_regress checks to see if the test
81+ * instance server has started and is available for connection.
82+ */
83+ #define WAIT_TICKS_PER_SECOND 20
84+
7885typedef enum TAPtype
7986{
8087 DIAG = 0 ,
@@ -107,6 +114,7 @@ static bool nolocale = false;
107114static bool use_existing = false;
108115static char * hostname = NULL ;
109116static int port = -1 ;
117+ static char portstr [16 ];
110118static bool port_specified_by_user = false;
111119static char * dlpath = PKGLIBDIR ;
112120static char * user = NULL ;
@@ -2107,7 +2115,6 @@ regression_main(int argc, char *argv[],
21072115 int i ;
21082116 int option_index ;
21092117 char buf [MAXPGPATH * 4 ];
2110- char buf2 [MAXPGPATH * 4 ];
21112118
21122119 pg_logging_init (argv [0 ]);
21132120 progname = get_progname (argv [0 ]);
@@ -2296,6 +2303,9 @@ regression_main(int argc, char *argv[],
22962303 const char * env_wait ;
22972304 int wait_seconds ;
22982305 const char * initdb_template_dir ;
2306+ const char * keywords [4 ];
2307+ const char * values [4 ];
2308+ PGPing rv ;
22992309
23002310 /*
23012311 * Prepare the temp instance
@@ -2436,21 +2446,28 @@ regression_main(int argc, char *argv[],
24362446#endif
24372447
24382448 /*
2439- * Check if there is a postmaster running already.
2449+ * Prepare the connection params for checking the state of the server
2450+ * before starting the tests.
24402451 */
2441- snprintf (buf2 , sizeof (buf2 ),
2442- "\"%s%spsql\" -X postgres <%s 2>%s" ,
2443- bindir ? bindir : "" ,
2444- bindir ? "/" : "" ,
2445- DEVNULL , DEVNULL );
2452+ sprintf (portstr , "%d" , port );
2453+ keywords [0 ] = "dbname" ;
2454+ values [0 ] = "postgres" ;
2455+ keywords [1 ] = "port" ;
2456+ values [1 ] = portstr ;
2457+ keywords [2 ] = "host" ;
2458+ values [2 ] = hostname ? hostname : sockdir ;
2459+ keywords [3 ] = NULL ;
2460+ values [3 ] = NULL ;
24462461
2462+ /*
2463+ * Check if there is a postmaster running already.
2464+ */
24472465 for (i = 0 ; i < 16 ; i ++ )
24482466 {
2449- fflush (NULL );
2450- if (system (buf2 ) == 0 )
2451- {
2452- char s [16 ];
2467+ rv = PQpingParams (keywords , values , 1 );
24532468
2469+ if (rv == PQPING_OK )
2470+ {
24542471 if (port_specified_by_user || i == 15 )
24552472 {
24562473 note ("port %d apparently in use" , port );
@@ -2461,8 +2478,8 @@ regression_main(int argc, char *argv[],
24612478
24622479 note ("port %d apparently in use, trying %d" , port , port + 1 );
24632480 port ++ ;
2464- sprintf (s , "%d" , port );
2465- setenv ("PGPORT" , s , 1 );
2481+ sprintf (portstr , "%d" , port );
2482+ setenv ("PGPORT" , portstr , 1 );
24662483 }
24672484 else
24682485 break ;
@@ -2485,11 +2502,11 @@ regression_main(int argc, char *argv[],
24852502 bail ("could not spawn postmaster: %s" , strerror (errno ));
24862503
24872504 /*
2488- * Wait till postmaster is able to accept connections; normally this
2489- * is only a second or so, but Cygwin is reportedly *much* slower, and
2490- * test builds using Valgrind or similar tools might be too. Hence,
2491- * allow the default timeout of 60 seconds to be overridden from the
2492- * PGCTLTIMEOUT environment variable.
2505+ * Wait till postmaster is able to accept connections; normally takes
2506+ * only a fraction of a second or so, but Cygwin is reportedly *much*
2507+ * slower, and test builds using Valgrind or similar tools might be
2508+ * too. Hence, allow the default timeout of 60 seconds to be
2509+ * overridden from the PGCTLTIMEOUT environment variable.
24932510 */
24942511 env_wait = getenv ("PGCTLTIMEOUT" );
24952512 if (env_wait != NULL )
@@ -2501,13 +2518,24 @@ regression_main(int argc, char *argv[],
25012518 else
25022519 wait_seconds = 60 ;
25032520
2504- for (i = 0 ; i < wait_seconds ; i ++ )
2521+ for (i = 0 ; i < wait_seconds * WAIT_TICKS_PER_SECOND ; i ++ )
25052522 {
2506- /* Done if psql succeeds */
2507- fflush (NULL );
2508- if (system (buf2 ) == 0 )
2523+ /*
2524+ * It's fairly unlikely that the server is responding immediately
2525+ * so we start with sleeping before checking instead of the other
2526+ * way around.
2527+ */
2528+ pg_usleep (1000000L / WAIT_TICKS_PER_SECOND );
2529+
2530+ rv = PQpingParams (keywords , values , 1 );
2531+
2532+ /* Done if the server is running and accepts connections */
2533+ if (rv == PQPING_OK )
25092534 break ;
25102535
2536+ if (rv == PQPING_NO_ATTEMPT )
2537+ bail ("attempting to connect to postmaster failed" );
2538+
25112539 /*
25122540 * Fail immediately if postmaster has exited
25132541 */
@@ -2520,10 +2548,8 @@ regression_main(int argc, char *argv[],
25202548 bail ("postmaster failed, examine \"%s/log/postmaster.log\" for the reason" ,
25212549 outputdir );
25222550 }
2523-
2524- pg_usleep (1000000L );
25252551 }
2526- if (i >= wait_seconds )
2552+ if (i >= wait_seconds * WAIT_TICKS_PER_SECOND )
25272553 {
25282554 diag ("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason" ,
25292555 wait_seconds , outputdir );
0 commit comments