]> granicus.if.org Git - postgresql/blobdiff - src/backend/access/transam/xlogarchive.c
Phase 2 of pgindent updates.
[postgresql] / src / backend / access / transam / xlogarchive.c
index 52922dae4ec34d8b4a112438084dce26fff164cb..7afb73579b009444f9b7df658645ea3f2cf5e5f5 100644 (file)
@@ -4,7 +4,7 @@
  *             Functions for archiving WAL files and restoring from the archive.
  *
  *
- * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * src/backend/access/transam/xlogarchive.c
@@ -14,7 +14,6 @@
 
 #include "postgres.h"
 
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <signal.h>
@@ -87,9 +86,9 @@ RestoreArchivedFile(char *path, const char *xlogfname,
         * of log segments that weren't yet transferred to the archive.
         *
         * Notice that we don't actually overwrite any files when we copy back
-        * from archive because the restore_command may inadvertently
-        * restore inappropriate xlogs, or they may be corrupt, so we may wish to
-        * fallback to the segments remaining in current XLOGDIR later. The
+        * from archive because the restore_command may inadvertently restore
+        * inappropriate xlogs, or they may be corrupt, so we may wish to fallback
+        * to the segments remaining in current XLOGDIR later. The
         * copy-from-archive filename is always the same, ensuring that we don't
         * run out of disk space on long recoveries.
         */
@@ -300,8 +299,8 @@ RestoreArchivedFile(char *path, const char *xlogfname,
        signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
 
        ereport(signaled ? FATAL : DEBUG2,
-               (errmsg("could not restore file \"%s\" from archive: return code %d",
-                               xlogfname, rc)));
+                       (errmsg("could not restore file \"%s\" from archive: %s",
+                                       xlogfname, wait_result_to_str(rc))));
 
 not_available:
 
@@ -410,9 +409,10 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
                ereport((signaled && failOnSignal) ? FATAL : WARNING,
                /*------
                   translator: First %s represents a recovery.conf parameter name like
-                 "recovery_end_command", and the 2nd is the value of that parameter. */
-                               (errmsg("%s \"%s\": return code %d", commandName,
-                                               command, rc)));
+                 "recovery_end_command", the 2nd is the value of that parameter, the
+                 third an already translated error message. */
+                               (errmsg("%s \"%s\": %s", commandName,
+                                               command, wait_result_to_str(rc))));
        }
 }
 
@@ -420,7 +420,7 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
 /*
  * A file was restored from the archive under a temporary filename (path),
  * and now we want to keep it. Rename it under the permanent filename in
- * in pg_xlog (xlogfname), replacing any existing file with the same name.
+ * in pg_wal (xlogfname), replacing any existing file with the same name.
  */
 void
 KeepFileRestoredFromArchive(char *path, char *xlogfname)
@@ -433,19 +433,20 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
 
        if (stat(xlogfpath, &statbuf) == 0)
        {
-               char oldpath[MAXPGPATH];
+               char            oldpath[MAXPGPATH];
+
 #ifdef WIN32
                static unsigned int deletedcounter = 1;
+
                /*
-                * On Windows, if another process (e.g a walsender process) holds
-                * the file open in FILE_SHARE_DELETE mode, unlink will succeed,
-                * but the file will still show up in directory listing until the
-                * last handle is closed, and we cannot rename the new file in its
-                * place until that. To avoid that problem, rename the old file to
-                * a temporary name first. Use a counter to create a unique
-                * filename, because the same file might be restored from the
-                * archive multiple times, and a walsender could still be holding
-                * onto an old deleted version of it.
+                * On Windows, if another process (e.g a walsender process) holds the
+                * file open in FILE_SHARE_DELETE mode, unlink will succeed, but the
+                * file will still show up in directory listing until the last handle
+                * is closed, and we cannot rename the new file in its place until
+                * that. To avoid that problem, rename the old file to a temporary
+                * name first. Use a counter to create a unique filename, because the
+                * same file might be restored from the archive multiple times, and a
+                * walsender could still be holding onto an old deleted version of it.
                 */
                snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
                                 xlogfpath, deletedcounter++);
@@ -457,7 +458,8 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
                                                        xlogfpath, oldpath)));
                }
 #else
-               strncpy(oldpath, xlogfpath, MAXPGPATH);
+               /* same-size buffers, so this never truncates */
+               strlcpy(oldpath, xlogfpath, MAXPGPATH);
 #endif
                if (unlink(oldpath) != 0)
                        ereport(FATAL,
@@ -467,18 +469,23 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
                reload = true;
        }
 
-       if (rename(path, xlogfpath) < 0)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not rename file \"%s\" to \"%s\": %m",
-                                               path, xlogfpath)));
+       durable_rename(path, xlogfpath, ERROR);
+
+       /*
+        * Create .done file forcibly to prevent the restored segment from being
+        * archived again later.
+        */
+       if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
+               XLogArchiveForceDone(xlogfname);
+       else
+               XLogArchiveNotify(xlogfname);
 
        /*
-        * If the existing file was replaced, since walsenders might have it
-        * open, request them to reload a currently-open segment. This is only
-        * required for WAL segments, walsenders don't hold other files open, but
-        * there's no harm in doing this too often, and we don't know what kind
-        * of a file we're dealing with here.
+        * If the existing file was replaced, since walsenders might have it open,
+        * request them to reload a currently-open segment. This is only required
+        * for WAL segments, walsenders don't hold other files open, but there's
+        * no harm in doing this too often, and we don't know what kind of a file
+        * we're dealing with here.
         */
        if (reload)
                WalSndRqstFileReload();
@@ -544,6 +551,54 @@ XLogArchiveNotifySeg(XLogSegNo segno)
        XLogArchiveNotify(xlog);
 }
 
+/*
+ * XLogArchiveForceDone
+ *
+ * Emit notification forcibly that an XLOG segment file has been successfully
+ * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
+ * exists or not.
+ */
+void
+XLogArchiveForceDone(const char *xlog)
+{
+       char            archiveReady[MAXPGPATH];
+       char            archiveDone[MAXPGPATH];
+       struct stat stat_buf;
+       FILE       *fd;
+
+       /* Exit if already known done */
+       StatusFilePath(archiveDone, xlog, ".done");
+       if (stat(archiveDone, &stat_buf) == 0)
+               return;
+
+       /* If .ready exists, rename it to .done */
+       StatusFilePath(archiveReady, xlog, ".ready");
+       if (stat(archiveReady, &stat_buf) == 0)
+       {
+               (void) durable_rename(archiveReady, archiveDone, WARNING);
+               return;
+       }
+
+       /* insert an otherwise empty file called <XLOG>.done */
+       fd = AllocateFile(archiveDone, "w");
+       if (fd == NULL)
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not create archive status file \"%s\": %m",
+                                               archiveDone)));
+               return;
+       }
+       if (FreeFile(fd))
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not write archive status file \"%s\": %m",
+                                               archiveDone)));
+               return;
+       }
+}
+
 /*
  * XLogArchiveCheckDone
  *
@@ -632,6 +687,60 @@ XLogArchiveIsBusy(const char *xlog)
        return true;
 }
 
+/*
+ * XLogArchiveIsReadyOrDone
+ *
+ * Check to see if an XLOG segment file has a .ready or .done file.
+ * This is similar to XLogArchiveIsBusy(), but returns true if the file
+ * is already archived or is about to be archived.
+ *
+ * This is currently only used at recovery.  During normal operation this
+ * would be racy: the file might get removed or marked with .ready as we're
+ * checking it, or immediately after we return.
+ */
+bool
+XLogArchiveIsReadyOrDone(const char *xlog)
+{
+       char            archiveStatusPath[MAXPGPATH];
+       struct stat stat_buf;
+
+       /* First check for .done --- this means archiver is done with it */
+       StatusFilePath(archiveStatusPath, xlog, ".done");
+       if (stat(archiveStatusPath, &stat_buf) == 0)
+               return true;
+
+       /* check for .ready --- this means archiver is still busy with it */
+       StatusFilePath(archiveStatusPath, xlog, ".ready");
+       if (stat(archiveStatusPath, &stat_buf) == 0)
+               return true;
+
+       /* Race condition --- maybe archiver just finished, so recheck */
+       StatusFilePath(archiveStatusPath, xlog, ".done");
+       if (stat(archiveStatusPath, &stat_buf) == 0)
+               return true;
+
+       return false;
+}
+
+/*
+ * XLogArchiveIsReady
+ *
+ * Check to see if an XLOG segment file has an archive notification (.ready)
+ * file.
+ */
+bool
+XLogArchiveIsReady(const char *xlog)
+{
+       char            archiveStatusPath[MAXPGPATH];
+       struct stat stat_buf;
+
+       StatusFilePath(archiveStatusPath, xlog, ".ready");
+       if (stat(archiveStatusPath, &stat_buf) == 0)
+               return true;
+
+       return false;
+}
+
 /*
  * XLogArchiveCleanup
  *