Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
In pg_ctl, work around ERROR_SHARING_VIOLATION on the postmaster log file.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 10 Dec 2019 18:17:08 +0000 (13:17 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 10 Dec 2019 18:17:08 +0000 (13:17 -0500)
On Windows, we use CMD.EXE to redirect the postmaster's stdout/stderr
into a log file.  CMD.EXE will open that file with non-sharing-friendly
parameters, and the file will remain open for a short time after the
postmaster has removed postmaster.pid.  This can result in an
ERROR_SHARING_VIOLATION failure if we attempt to start a new postmaster
immediately with the same log file (e.g. during "pg_ctl restart").
This seems to explain intermittent buildfarm failures we've been seeing
on Windows machines.

To fix, just open and close the log file using our own pgwin32_open(),
which will wait if necessary to avoid the failure.  (Perhaps someday
we should stop using CMD.EXE, but that would be a far more complex
patch, and it doesn't seem worth the trouble ... yet.)

Back-patch to v12.  This only solves the problem when frontend fopen()
is redirected to pgwin32_fopen(), which has only been true since commit
0ba06e0bf.  Hence, no point in back-patching further, unless we care
to back-patch that change too.

Diagnosis and patch by Alexander Lakhin (bug #16154).

Discussion: https://postgr.es/m/16154-1ccf0b537b24d5e0@postgresql.org

src/bin/pg_ctl/pg_ctl.c

index 65f9fb4c0a92910045720810f604864c5dcb959a..b0858411ed96e94c0c49372978259868e5aa33d3 100644 (file)
@@ -519,8 +519,29 @@ start_postmaster(void)
        comspec = "CMD";
 
    if (log_file != NULL)
+   {
+       /*
+        * First, touch the log file.  The main value of this is that if the
+        * file is still locked by a previous postmaster run, we'll wait until
+        * it comes free, instead of failing with ERROR_SHARING_VIOLATION.
+        * (It'd be better to open the file in a sharing-friendly mode, but we
+        * can't use CMD.EXE to do that, so work around it.  Note that the
+        * previous postmaster will still have the file open for a short time
+        * after removing postmaster.pid.)
+        */
+       FILE       *fd = fopen(log_file, "a");
+
+       if (fd == NULL)
+       {
+           write_stderr(_("%s: could not create log file \"%s\": %s\n"),
+                        progname, log_file, strerror(errno));
+           exit(1);
+       }
+       fclose(fd);
+
        snprintf(cmd, MAXPGPATH, "\"%s\" /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
                 comspec, exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
+   }
    else
        snprintf(cmd, MAXPGPATH, "\"%s\" /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
                 comspec, exec_path, pgdata_opt, post_opts, DEVNULL);