(unnamed)
text/plain
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 26b023e754..037da0aa3d 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -382,6 +382,7 @@ KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
{
char xlogfpath[MAXPGPATH];
bool reload = false;
+ bool skip_archive = false;
struct stat statbuf;
snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
@@ -416,6 +417,56 @@ KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
/* same-size buffers, so this never truncates */
strlcpy(oldpath, xlogfpath, MAXPGPATH);
#endif
+ /*
+ * On a standby with archive_mode=always, there's the case where the
+ * same file is archived more than once. If the archive_command rejects
+ * overwriting, WAL-archiving won't go further than the file forever.
+ * Avoid duplicate archiving attempts when the file is known to have
+ * been archived and the content doesn't change.
+ */
+ if (XLogArchiveMode == ARCHIVE_MODE_ALWAYS &&
+ XLogArchiveCheckDone(xlogfname))
+ {
+ unsigned char srcbuf[XLOG_BLCKSZ];
+ unsigned char dstbuf[XLOG_BLCKSZ];
+ int fd1 = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+ int fd2 = BasicOpenFile(oldpath, O_RDONLY | PG_BINARY);
+ uint32 i;
+ uint32 off = 0;
+
+ /*
+ * Compare the two files' contents. We don't bother completing if
+ * something's wrong meanwhile.
+ */
+ for (i = 0 ; i < wal_segment_size / XLOG_BLCKSZ ; i++)
+ {
+ if (pg_pread(fd1, srcbuf, XLOG_BLCKSZ, (off_t) off)
+ != XLOG_BLCKSZ)
+ break;
+
+ if (pg_pread(fd2, dstbuf, XLOG_BLCKSZ, (off_t) off)
+ != XLOG_BLCKSZ)
+ break;
+
+ if (memcmp(srcbuf, dstbuf, XLOG_BLCKSZ) != 0)
+ break;
+
+ off += XLOG_BLCKSZ;
+ }
+
+ close(fd1);
+ close(fd2);
+
+ if (i == wal_segment_size / XLOG_BLCKSZ)
+ {
+ skip_archive = true;
+
+ ereport(LOG,
+ (errmsg ("log file \"%s\" have been already archived, skip archiving",
+ xlogfname)));
+ }
+ }
+
if (unlink(oldpath) != 0)
ereport(FATAL,
(errcode_for_file_access(),
@@ -430,7 +481,7 @@ KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
* Create .done file forcibly to prevent the restored segment from being
* archived again later.
*/
- if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
+ if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS || skip_archive)
XLogArchiveForceDone(xlogfname);
else
XLogArchiveNotify(xlogfname);