Skip to content

Commit 815fcd0

Browse files
committed
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.
1 parent 5691de6 commit 815fcd0

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

contrib/pg_upgrade/exec.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,29 @@ static int win32_check_directory_write_permissions(void);
3737
* If throw_error is true, this raises a PG_FATAL error and pg_upgrade
3838
* terminates; otherwise it is just reported as PG_REPORT and exec_prog()
3939
* returns false.
40+
*
41+
* The code requires it be called first from the primary thread on Windows.
4042
*/
4143
bool
4244
exec_prog(const char *log_file, const char *opt_log_file,
4345
bool throw_error, const char *fmt,...)
4446
{
45-
int result;
47+
int result = 0;
4648
int written;
4749

4850
#define MAXCMDLEN (2 * MAXPGPATH)
4951
char cmd[MAXCMDLEN];
5052
FILE *log;
5153
va_list ap;
5254

55+
#ifdef WIN32
56+
static DWORD mainThreadId = 0;
57+
58+
/* We assume we are called from the primary thread first */
59+
if (mainThreadId == 0)
60+
mainThreadId = GetCurrentThreadId();
61+
#endif
62+
5363
written = strlcpy(cmd, SYSTEMQUOTE, sizeof(cmd));
5464
va_start(ap, fmt);
5565
written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);
@@ -61,6 +71,22 @@ exec_prog(const char *log_file, const char *opt_log_file,
6171
if (written >= MAXCMDLEN)
6272
pg_log(PG_FATAL, "command too long\n");
6373

74+
pg_log(PG_VERBOSE, "%s\n", cmd);
75+
76+
#ifdef WIN32
77+
/*
78+
* For some reason, Windows issues a file-in-use error if we write data
79+
* to the log file from a non-primary thread just before we create a
80+
* subprocess that also writes to the same log file. One fix is to
81+
* sleep for 100ms. A cleaner fix is to write to the log file _after_
82+
* the subprocess has completed, so we do this only when writing from
83+
* a non-primary thread. fflush(), running system() twice, and
84+
* pre-creating the file do not see to help.
85+
*/
86+
if (mainThreadId != GetCurrentThreadId())
87+
result = system(cmd);
88+
#endif
89+
6490
log = fopen(log_file, "a");
6591

6692
#ifdef WIN32
@@ -84,19 +110,30 @@ exec_prog(const char *log_file, const char *opt_log_file,
84110

85111
if (log == NULL)
86112
pg_log(PG_FATAL, "cannot write to log file %s\n", log_file);
113+
87114
#ifdef WIN32
88-
fprintf(log, "\n\n");
115+
/* Are we printing "command:" before its output? */
116+
if (mainThreadId == GetCurrentThreadId())
117+
fprintf(log, "\n\n");
89118
#endif
90-
pg_log(PG_VERBOSE, "%s\n", cmd);
91119
fprintf(log, "command: %s\n", cmd);
120+
#ifdef WIN32
121+
/* Are we printing "command:" after its output? */
122+
if (mainThreadId != GetCurrentThreadId())
123+
fprintf(log, "\n\n");
124+
#endif
92125

93126
/*
94127
* In Windows, we must close the log file at this point so the file is not
95128
* open while the command is running, or we get a share violation.
96129
*/
97130
fclose(log);
98131

99-
result = system(cmd);
132+
#ifdef WIN32
133+
/* see comment above */
134+
if (mainThreadId == GetCurrentThreadId())
135+
#endif
136+
result = system(cmd);
100137

101138
if (result != 0)
102139
{
@@ -118,7 +155,6 @@ exec_prog(const char *log_file, const char *opt_log_file,
118155
}
119156

120157
#ifndef WIN32
121-
122158
/*
123159
* We can't do this on Windows because it will keep the "pg_ctl start"
124160
* output filename open until the server stops, so we do the \n\n above on

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy