]> granicus.if.org Git - postgresql/blobdiff - src/backend/access/transam/xlogarchive.c
Fix initialization of fake LSN for unlogged relations
[postgresql] / src / backend / access / transam / xlogarchive.c
index 52922dae4ec34d8b4a112438084dce26fff164cb..e14bcf8ea6092fb40a7618ba1a6b76ba4411bbad 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-2019, 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>
  * Attempt to retrieve the specified file from off-line archival storage.
  * If successful, fill "path" with its complete path (note that this will be
  * a temp file name that doesn't follow the normal naming convention), and
- * return TRUE.
+ * return true.
  *
  * If not successful, fill "path" with the name of the normal on-line file
  * (which may or may not actually exist, but we'll try to use it), and return
- * FALSE.
+ * false.
  *
  * For fixed-size files, the caller may pass the expected size as an
  * additional crosscheck on successful recovery.  If the file size is not
@@ -60,14 +59,20 @@ RestoreArchivedFile(char *path, const char *xlogfname,
        char       *endp;
        const char *sp;
        int                     rc;
-       bool            signaled;
        struct stat stat_buf;
        XLogSegNo       restartSegNo;
        XLogRecPtr      restartRedoPtr;
        TimeLineID      restartTli;
 
+       /*
+        * Ignore restore_command when not in archive recovery (meaning
+        * we are in crash recovery).
+        */
+       if (!ArchiveRecoveryRequested)
+               goto not_available;
+
        /* In standby mode, restore_command might not be supplied */
-       if (recoveryRestoreCommand == NULL)
+       if (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0)
                goto not_available;
 
        /*
@@ -87,9 +92,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.
         */
@@ -135,13 +140,14 @@ RestoreArchivedFile(char *path, const char *xlogfname,
        if (cleanupEnabled)
        {
                GetOldestRestartPoint(&restartRedoPtr, &restartTli);
-               XLByteToSeg(restartRedoPtr, restartSegNo);
-               XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+               XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+               XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+                                        wal_segment_size);
                /* we shouldn't need anything earlier than last restart point */
                Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
        }
        else
-               XLogFileName(lastRestartPointFname, 0, 0L);
+               XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
 
        /*
         * construct the command to be executed
@@ -289,19 +295,14 @@ RestoreArchivedFile(char *path, const char *xlogfname,
         * will perform an immediate shutdown when it sees us exiting
         * unexpectedly.
         *
-        * Per the Single Unix Spec, shells report exit status > 128 when a called
-        * command died on a signal.  Also, 126 and 127 are used to report
-        * problems such as an unfindable command; treat those as fatal errors
-        * too.
+        * We treat hard shell errors such as "command not found" as fatal, too.
         */
-       if (WIFSIGNALED(rc) && WTERMSIG(rc) == SIGTERM)
+       if (wait_result_is_signal(rc, SIGTERM))
                proc_exit(1);
 
-       signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
-
-       ereport(signaled ? FATAL : DEBUG2,
-               (errmsg("could not restore file \"%s\" from archive: return code %d",
-                               xlogfname, rc)));
+       ereport(wait_result_is_any_signal(rc, true) ? FATAL : DEBUG2,
+                       (errmsg("could not restore file \"%s\" from archive: %s",
+                                       xlogfname, wait_result_to_str(rc))));
 
 not_available:
 
@@ -327,7 +328,7 @@ not_available:
  * This is currently used for recovery_end_command and archive_cleanup_command.
  */
 void
-ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
+ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOnSignal)
 {
        char            xlogRecoveryCmd[MAXPGPATH];
        char            lastRestartPointFname[MAXPGPATH];
@@ -335,7 +336,6 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
        char       *endp;
        const char *sp;
        int                     rc;
-       bool            signaled;
        XLogSegNo       restartSegNo;
        XLogRecPtr      restartRedoPtr;
        TimeLineID      restartTli;
@@ -348,8 +348,9 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
         * archive, though there is no requirement to do so.
         */
        GetOldestRestartPoint(&restartRedoPtr, &restartTli);
-       XLByteToSeg(restartRedoPtr, restartSegNo);
-       XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+       XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+       XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+                                wal_segment_size);
 
        /*
         * construct the command to be executed
@@ -402,17 +403,15 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
        {
                /*
                 * If the failure was due to any sort of signal, it's best to punt and
-                * abort recovery. See also detailed comments on signals in
-                * RestoreArchivedFile().
+                * abort recovery.  See comments in RestoreArchivedFile().
                 */
-               signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
-
-               ereport((signaled && failOnSignal) ? FATAL : WARNING,
+               ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? 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)));
+                  translator: First %s represents a postgresql.conf parameter name like
+                 "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,10 +419,10 @@ 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.
+ * pg_wal (xlogfname), replacing any existing file with the same name.
  */
 void
-KeepFileRestoredFromArchive(char *path, char *xlogfname)
+KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
 {
        char            xlogfpath[MAXPGPATH];
        bool            reload = false;
@@ -433,19 +432,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 +457,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 +468,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();
@@ -540,10 +546,58 @@ XLogArchiveNotifySeg(XLogSegNo segno)
 {
        char            xlog[MAXFNAMELEN];
 
-       XLogFileName(xlog, ThisTimeLineID, segno);
+       XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
        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
  *
@@ -563,9 +617,16 @@ XLogArchiveCheckDone(const char *xlog)
 {
        char            archiveStatusPath[MAXPGPATH];
        struct stat stat_buf;
+       bool            inRecovery = RecoveryInProgress();
 
-       /* Always deletable if archiving is off */
-       if (!XLogArchivingActive())
+       /*
+        * The file is always deletable if archive_mode is "off".  On standbys
+        * archiving is disabled if archive_mode is "on", and enabled with
+        * "always".  On a primary, archiving is enabled if archive_mode is "on"
+        * or "always".
+        */
+       if (!((XLogArchivingActive() && !inRecovery) ||
+                 (XLogArchivingAlways() && inRecovery)))
                return true;
 
        /* First check for .done --- this means archiver is done with it */
@@ -632,6 +693,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
  *