Change Windows rename and unlink substitutes so that they time out after
authorTom Lane
Wed, 8 Nov 2006 20:12:05 +0000 (20:12 +0000)
committerTom Lane
Wed, 8 Nov 2006 20:12:05 +0000 (20:12 +0000)
30 seconds instead of retrying forever.  Also modify xlog.c so that if
it fails to rename an old xlog segment up to a future slot, it will
unlink the segment instead.  Per discussion of bug #2712, in which it
became apparent that Windows can handle unlinking a file that's being
held open, but not renaming it.

src/backend/access/transam/xlog.c
src/port/dirmod.c

index 03440cbf48ba92b240b2a61587859c8a9db7c1c8..9b590061731a2d80ebe5b136a0c53edd9164f026 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.253 2006/11/05 22:42:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.254 2006/11/08 20:12:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2140,7 +2140,9 @@ XLogFileCopy(uint32 log, uint32 seg,
  * caller must *not* hold the lock at call.
  *
  * Returns TRUE if file installed, FALSE if not installed because of
- * exceeding max_advance limit.  (Any other kind of failure causes ereport().)
+ * exceeding max_advance limit.  On Windows, we also return FALSE if we
+ * can't rename the file into place because someone's got it open.
+ * (Any other kind of failure causes ereport().)
  */
 static bool
 InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
@@ -2195,10 +2197,25 @@ InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
    unlink(tmppath);
 #else
    if (rename(tmppath, path) < 0)
+   {
+#ifdef WIN32
+#if !defined(__CYGWIN__)
+       if (GetLastError() == ERROR_ACCESS_DENIED)
+#else
+       if (errno == EACCES)
+#endif
+       {
+           if (use_lock)
+               LWLockRelease(ControlFileLock);
+           return false;
+       }
+#endif /* WIN32 */
+
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file %u, segment %u): %m",
                        tmppath, path, *log, *seg)));
+   }
 #endif
 
    if (use_lock)
index e58384a749cbc59b8afaf0fbedca7a8cdab15277..3934b5cf7dd6c40fb8e5e940428d5ab709a7ad22 100644 (file)
@@ -10,7 +10,7 @@
  * Win32 (NT, Win2k, XP).  replace() doesn't work on Win95/98/Me.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/port/dirmod.c,v 1.43 2006/07/18 22:36:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/port/dirmod.c,v 1.44 2006/11/08 20:12:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,43 +117,28 @@ pgrename(const char *from, const char *to)
    int         loops = 0;
 
    /*
-    * We need these loops because even though PostgreSQL uses flags that
+    * We need to loop because even though PostgreSQL uses flags that
     * allow rename while the file is open, other applications might have
-    * these files open without those flags.
+    * the file open without those flags.  However, we won't wait
+    * indefinitely for someone else to close the file.
     */
 #if defined(WIN32) && !defined(__CYGWIN__)
    while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
-#endif
-#ifdef __CYGWIN__
-       while (rename(from, to) < 0)
-#endif
-       {
-#if defined(WIN32) && !defined(__CYGWIN__)
-           if (GetLastError() != ERROR_ACCESS_DENIED)
-#endif
-#ifdef __CYGWIN__
-               if (errno != EACCES)
-#endif
-                   /* set errno? */
-                   return -1;
-           pg_usleep(100000);  /* us */
-           if (loops == 30)
-#ifndef FRONTEND
-               elog(LOG, "could not rename file \"%s\" to \"%s\", continuing to try",
-                    from, to);
 #else
-               fprintf(stderr, _("could not rename file \"%s\" to \"%s\", continuing to try\n"),
-                       from, to);
+   while (rename(from, to) < 0)
 #endif
-           loops++;
-       }
-
-   if (loops > 30)
-#ifndef FRONTEND
-       elog(LOG, "completed rename of file \"%s\" to \"%s\"", from, to);
+   {
+#if defined(WIN32) && !defined(__CYGWIN__)
+       if (GetLastError() != ERROR_ACCESS_DENIED)
 #else
-       fprintf(stderr, _("completed rename of file \"%s\" to \"%s\"\n"), from, to);
+       if (errno != EACCES)
 #endif
+           /* set errno? */
+           return -1;
+       if (++loops > 300)      /* time out after 30 sec */
+           return -1;
+       pg_usleep(100000);      /* us */
+   }
    return 0;
 }
 
@@ -167,33 +152,20 @@ pgunlink(const char *path)
    int         loops = 0;
 
    /*
-    * We need these loops because even though PostgreSQL uses flags that
+    * We need to loop because even though PostgreSQL uses flags that
     * allow unlink while the file is open, other applications might have
-    * these files open without those flags.
+    * the file open without those flags.  However, we won't wait
+    * indefinitely for someone else to close the file.
     */
    while (unlink(path))
    {
        if (errno != EACCES)
            /* set errno? */
            return -1;
+       if (++loops > 300)      /* time out after 30 sec */
+           return -1;
        pg_usleep(100000);      /* us */
-       if (loops == 30)
-#ifndef FRONTEND
-           elog(LOG, "could not remove file \"%s\", continuing to try",
-                path);
-#else
-           fprintf(stderr, _("could not remove file \"%s\", continuing to try\n"),
-                   path);
-#endif
-       loops++;
    }
-
-   if (loops > 30)
-#ifndef FRONTEND
-       elog(LOG, "completed removal of file \"%s\"", path);
-#else
-       fprintf(stderr, _("completed removal of file \"%s\"\n"), path);
-#endif
    return 0;
 }