- Fix the -w (wait) option to work in Windows service mode, per bug #3382.

- Prevent the -w option being passed to the postmaster.
- Read the postmaster options file when starting as a Windows service.

Dave Page
This commit is contained in:
Magnus Hagander 2007-07-02 21:58:31 +00:00
parent 1c7fe33fdb
commit a1587e41ae

View File

@ -4,7 +4,7 @@
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.80 2007/05/31 15:13:04 petere Exp $
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.81 2007/07/02 21:58:31 mha Exp $
*
*-------------------------------------------------------------------------
*/
@ -126,11 +126,22 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
static void pgwin32_doRunAsService(void);
static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION * processInfo);
static SERVICE_STATUS status;
static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
static HANDLE shutdownHandles[2];
static pid_t postmasterPID = -1;
#define shutdownEvent shutdownHandles[0]
#define postmasterProcess shutdownHandles[1]
#endif
static pgpid_t get_pgpid(void);
static char **readfile(const char *path);
static int start_postmaster(void);
static bool test_postmaster_connection(void);
static int start_postmaster(void);
static void read_post_opts(void);
static bool test_postmaster_connection(bool);
static bool postmaster_is_alive(pid_t pid);
static char def_postopts_file[MAXPGPATH];
@ -391,15 +402,20 @@ start_postmaster(void)
/* Find the pgport and try a connection */
/*
* Find the pgport and try a connection
* Note that the checkpoint parameter enables a Windows service control
* manager checkpoint, it's got nothing to do with database checkpoints!!
*/
static bool
test_postmaster_connection(void)
test_postmaster_connection(bool do_checkpoint)
{
PGconn *conn;
bool success = false;
int i;
char portstr[32];
char *p;
char connstr[128]; /* Should be way more than enough! */
*portstr = '\0';
@ -464,10 +480,12 @@ test_postmaster_connection(void)
if (!*portstr)
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++)
{
if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL,
"postgres", NULL, NULL)) != NULL &&
if ((conn = PQconnectdb(connstr)) != NULL &&
(PQstatus(conn) == CONNECTION_OK ||
(strcmp(PQerrorMessage(conn),
PQnoPasswordSupplied) == 0)))
@ -479,7 +497,25 @@ test_postmaster_connection(void)
else
{
PQfinish(conn);
print_msg(".");
#if defined(WIN32)
if (do_checkpoint)
{
/*
* Increment the wait hint by 6 secs (connection timeout + sleep)
* We must do this to indicate to the SCM that our startup time is
* changing, otherwise it'll usually send a stop signal after 20
* seconds, despite incrementing the checkpoint counter.
*/
status.dwWaitHint += 6000;
status.dwCheckPoint++;
SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
}
else
#endif
print_msg(".");
pg_usleep(1000000); /* 1 sec */
}
}
@ -508,24 +544,10 @@ unlimit_core_size(void)
}
#endif
static void
do_start(void)
read_post_opts(void)
{
pgpid_t pid;
pgpid_t old_pid = 0;
char *optline = NULL;
int exitcode;
if (ctl_command != RESTART_COMMAND)
{
old_pid = get_pgpid();
if (old_pid != 0)
write_stderr(_("%s: another server might be running; "
"trying to start server anyway\n"),
progname);
}
if (post_opts == NULL)
{
@ -536,7 +558,7 @@ do_start(void)
postopts_file : def_postopts_file);
if (optlines == NULL)
{
if (ctl_command == START_COMMAND)
if (ctl_command == START_COMMAND || ctl_command == RUN_AS_SERVICE_COMMAND)
post_opts = "";
else
{
@ -576,6 +598,25 @@ do_start(void)
post_opts = optline;
}
}
}
static void
do_start(void)
{
pgpid_t pid;
pgpid_t old_pid = 0;
int exitcode;
if (ctl_command != RESTART_COMMAND)
{
old_pid = get_pgpid();
if (old_pid != 0)
write_stderr(_("%s: another server might be running; "
"trying to start server anyway\n"),
progname);
}
read_post_opts();
/* No -D or -D already added during server start */
if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
@ -642,7 +683,7 @@ do_start(void)
{
print_msg(_("waiting for server to start..."));
if (test_postmaster_connection() == false)
if (test_postmaster_connection(false) == false)
{
printf(_("could not start server\n"));
exit(1);
@ -982,7 +1023,7 @@ pgwin32_CommandLine(bool registration)
strcat(cmdLine, "\"");
}
if (do_wait)
if (registration && do_wait)
strcat(cmdLine, " -w");
if (post_opts)
@ -1065,15 +1106,6 @@ pgwin32_doUnregister(void)
CloseServiceHandle(hSCM);
}
static SERVICE_STATUS status;
static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
static HANDLE shutdownHandles[2];
static pid_t postmasterPID = -1;
#define shutdownEvent shutdownHandles[0]
#define postmasterProcess shutdownHandles[1]
static void
pgwin32_SetServiceStatus(DWORD currentState)
{
@ -1118,6 +1150,7 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
{
PROCESS_INFORMATION pi;
DWORD ret;
DWORD check_point_start;
/* Initialize variables */
status.dwWin32ExitCode = S_OK;
@ -1130,6 +1163,8 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
memset(&pi, 0, sizeof(pi));
read_post_opts();
/* Register the control request handler */
if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
return;
@ -1147,10 +1182,27 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
postmasterPID = pi.dwProcessId;
postmasterProcess = pi.hProcess;
CloseHandle(pi.hThread);
if (do_wait)
{
write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
if (test_postmaster_connection(true) == false)
{
write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Timed out waiting for server startup\n"));
pgwin32_SetServiceStatus(SERVICE_STOPPED);
return;
}
write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
}
/* Save the checkpoint value as it might have been incremented in test_postmaster_connection */
check_point_start = status.dwCheckPoint;
pgwin32_SetServiceStatus(SERVICE_RUNNING);
/* Wait for quit... */
ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
switch (ret)
{