summaryrefslogtreecommitdiffstats
path: root/src/fe_utils/archive.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe_utils/archive.c')
-rw-r--r--src/fe_utils/archive.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/fe_utils/archive.c b/src/fe_utils/archive.c
new file mode 100644
index 0000000..1e9d994
--- /dev/null
+++ b/src/fe_utils/archive.c
@@ -0,0 +1,124 @@
+/*-------------------------------------------------------------------------
+ *
+ * archive.c
+ * Routines to access WAL archives from frontend
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/fe_utils/archive.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "access/xlog_internal.h"
+#include "common/archive.h"
+#include "common/logging.h"
+#include "fe_utils/archive.h"
+
+
+/*
+ * RestoreArchivedFile
+ *
+ * Attempt to retrieve the specified file from off-line archival storage.
+ * If successful, return a file descriptor of the restored file, else
+ * return -1.
+ *
+ * For fixed-size files, the caller may pass the expected size as an
+ * additional crosscheck on successful recovery. If the file size is not
+ * known, set expectedSize = 0.
+ */
+int
+RestoreArchivedFile(const char *path, const char *xlogfname,
+ off_t expectedSize, const char *restoreCommand)
+{
+ char xlogpath[MAXPGPATH];
+ char *xlogRestoreCmd;
+ int rc;
+ struct stat stat_buf;
+
+ snprintf(xlogpath, MAXPGPATH, "%s/" XLOGDIR "/%s", path, xlogfname);
+
+ xlogRestoreCmd = BuildRestoreCommand(restoreCommand, xlogpath,
+ xlogfname, NULL);
+ if (xlogRestoreCmd == NULL)
+ {
+ pg_log_fatal("cannot use restore_command with %%r placeholder");
+ exit(1);
+ }
+
+ /*
+ * Execute restore_command, which should copy the missing file from
+ * archival storage.
+ */
+ rc = system(xlogRestoreCmd);
+ pfree(xlogRestoreCmd);
+
+ if (rc == 0)
+ {
+ /*
+ * Command apparently succeeded, but let's make sure the file is
+ * really there now and has the correct size.
+ */
+ if (stat(xlogpath, &stat_buf) == 0)
+ {
+ if (expectedSize > 0 && stat_buf.st_size != expectedSize)
+ {
+ pg_log_fatal("unexpected file size for \"%s\": %lu instead of %lu",
+ xlogfname, (unsigned long) stat_buf.st_size,
+ (unsigned long) expectedSize);
+ exit(1);
+ }
+ else
+ {
+ int xlogfd = open(xlogpath, O_RDONLY | PG_BINARY, 0);
+
+ if (xlogfd < 0)
+ {
+ pg_log_fatal("could not open file \"%s\" restored from archive: %m",
+ xlogpath);
+ exit(1);
+ }
+ else
+ return xlogfd;
+ }
+ }
+ else
+ {
+ if (errno != ENOENT)
+ {
+ pg_log_fatal("could not stat file \"%s\": %m",
+ xlogpath);
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * If the failure was due to a signal, then it would be misleading to
+ * return with a failure at restoring the file. So just bail out and
+ * exit. Hard shell errors such as "command not found" are treated as
+ * fatal too.
+ */
+ if (wait_result_is_any_signal(rc, true))
+ {
+ pg_log_fatal("restore_command failed: %s",
+ wait_result_to_str(rc));
+ exit(1);
+ }
+
+ /*
+ * The file is not available, so just let the caller decide what to do
+ * next.
+ */
+ pg_log_error("could not restore file \"%s\" from archive",
+ xlogfname);
+ return -1;
+}