(unnamed)

text/plain

Filename: (unnamed)
Type: text/plain
Part: 1
Message: Re: Duplicate history file?
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);