OSDN Git Service

Change Windows rename and unlink substitutes so that they time out after
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 8 Nov 2006 20:12:05 +0000 (20:12 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 03440cb..9b59006 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 e58384a..3934b5c 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;
 }