mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
pg_upgrade: fix -j race condition on Windows
Pg_Upgrade cannot write the command string to the log file and then call system() to write to the same file without causing occasional file-share errors on Windows. So instead, write the command string to the log file after system(), in those cases. Backpatch to 9.3.
This commit is contained in:
parent
61edd52401
commit
d83940a7f6
@ -37,12 +37,14 @@ static int win32_check_directory_write_permissions(void);
|
|||||||
* If throw_error is true, this raises a PG_FATAL error and pg_upgrade
|
* If throw_error is true, this raises a PG_FATAL error and pg_upgrade
|
||||||
* terminates; otherwise it is just reported as PG_REPORT and exec_prog()
|
* terminates; otherwise it is just reported as PG_REPORT and exec_prog()
|
||||||
* returns false.
|
* returns false.
|
||||||
|
*
|
||||||
|
* The code requires it be called first from the primary thread on Windows.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
exec_prog(const char *log_file, const char *opt_log_file,
|
exec_prog(const char *log_file, const char *opt_log_file,
|
||||||
bool throw_error, const char *fmt,...)
|
bool throw_error, const char *fmt,...)
|
||||||
{
|
{
|
||||||
int result;
|
int result = 0;
|
||||||
int written;
|
int written;
|
||||||
|
|
||||||
#define MAXCMDLEN (2 * MAXPGPATH)
|
#define MAXCMDLEN (2 * MAXPGPATH)
|
||||||
@ -50,6 +52,14 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
FILE *log;
|
FILE *log;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static DWORD mainThreadId = 0;
|
||||||
|
|
||||||
|
/* We assume we are called from the primary thread first */
|
||||||
|
if (mainThreadId == 0)
|
||||||
|
mainThreadId = GetCurrentThreadId();
|
||||||
|
#endif
|
||||||
|
|
||||||
written = strlcpy(cmd, SYSTEMQUOTE, sizeof(cmd));
|
written = strlcpy(cmd, SYSTEMQUOTE, sizeof(cmd));
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);
|
written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);
|
||||||
@ -61,6 +71,22 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
if (written >= MAXCMDLEN)
|
if (written >= MAXCMDLEN)
|
||||||
pg_log(PG_FATAL, "command too long\n");
|
pg_log(PG_FATAL, "command too long\n");
|
||||||
|
|
||||||
|
pg_log(PG_VERBOSE, "%s\n", cmd);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/*
|
||||||
|
* For some reason, Windows issues a file-in-use error if we write data
|
||||||
|
* to the log file from a non-primary thread just before we create a
|
||||||
|
* subprocess that also writes to the same log file. One fix is to
|
||||||
|
* sleep for 100ms. A cleaner fix is to write to the log file _after_
|
||||||
|
* the subprocess has completed, so we do this only when writing from
|
||||||
|
* a non-primary thread. fflush(), running system() twice, and
|
||||||
|
* pre-creating the file do not see to help.
|
||||||
|
*/
|
||||||
|
if (mainThreadId != GetCurrentThreadId())
|
||||||
|
result = system(cmd);
|
||||||
|
#endif
|
||||||
|
|
||||||
log = fopen(log_file, "a");
|
log = fopen(log_file, "a");
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -84,11 +110,18 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
|
|
||||||
if (log == NULL)
|
if (log == NULL)
|
||||||
pg_log(PG_FATAL, "cannot write to log file %s\n", log_file);
|
pg_log(PG_FATAL, "cannot write to log file %s\n", log_file);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
fprintf(log, "\n\n");
|
/* Are we printing "command:" before its output? */
|
||||||
|
if (mainThreadId == GetCurrentThreadId())
|
||||||
|
fprintf(log, "\n\n");
|
||||||
#endif
|
#endif
|
||||||
pg_log(PG_VERBOSE, "%s\n", cmd);
|
|
||||||
fprintf(log, "command: %s\n", cmd);
|
fprintf(log, "command: %s\n", cmd);
|
||||||
|
#ifdef WIN32
|
||||||
|
/* Are we printing "command:" after its output? */
|
||||||
|
if (mainThreadId != GetCurrentThreadId())
|
||||||
|
fprintf(log, "\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In Windows, we must close the log file at this point so the file is not
|
* In Windows, we must close the log file at this point so the file is not
|
||||||
@ -96,7 +129,11 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
*/
|
*/
|
||||||
fclose(log);
|
fclose(log);
|
||||||
|
|
||||||
result = system(cmd);
|
#ifdef WIN32
|
||||||
|
/* see comment above */
|
||||||
|
if (mainThreadId == GetCurrentThreadId())
|
||||||
|
#endif
|
||||||
|
result = system(cmd);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
@ -118,7 +155,6 @@ exec_prog(const char *log_file, const char *opt_log_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't do this on Windows because it will keep the "pg_ctl start"
|
* We can't do this on Windows because it will keep the "pg_ctl start"
|
||||||
* output filename open until the server stops, so we do the \n\n above on
|
* output filename open until the server stops, so we do the \n\n above on
|
||||||
|
Loading…
x
Reference in New Issue
Block a user