avoid_duplicate_archiving_PoC2.patch

text/x-patch

Filename: avoid_duplicate_archiving_PoC2.patch
Type: text/x-patch
Part: 1
Message: Re: Duplicate history file?

Patch

Format: unified
File+
src/backend/access/transam/xlogarchive.c 64 1
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 26b023e754..7d94e7f963 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		already_archived = false;
 	struct stat statbuf;
 
 	snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname);
@@ -416,6 +417,68 @@ 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 with the same
+		 * content is known to have been already archived or notified.
+		 */
+		if (XLogArchiveMode == ARCHIVE_MODE_ALWAYS &&
+			XLogArchiveIsReadyOrDone(xlogfname))
+		{
+			int fd1;
+			int fd2 = -1;
+
+			fd1 = BasicOpenFile(path, O_RDONLY | PG_BINARY);
+			if (fd1 >= 0)
+				fd2 = BasicOpenFile(oldpath, O_RDONLY | PG_BINARY);
+
+			if (fd1 < 0 || fd2 < 0)
+			{
+				ereport(WARNING,
+						(errcode_for_file_access(),
+						 errmsg("could not open file \"%s\", skip duplicate check: %m",
+								fd1 < 0 ? path : oldpath)));
+				if (fd1 >= 0)
+					close(fd1);
+			}
+			else
+			{
+				unsigned char srcbuf[XLOG_BLCKSZ];
+				unsigned char dstbuf[XLOG_BLCKSZ];
+				uint32 i;
+
+				/*
+				 * 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 (read(fd1, srcbuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+						break;
+
+					if (read(fd2, dstbuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+						break;
+
+					if (memcmp(srcbuf, dstbuf, XLOG_BLCKSZ) != 0)
+						break;
+				}
+
+				close(fd1);
+				close(fd2);
+
+				if (i == wal_segment_size / XLOG_BLCKSZ)
+				{
+					already_archived = true;
+
+					ereport(LOG,
+							(errmsg("log file \"%s\" have been already archived, skip archiving",
+									xlogfname)));
+				}
+			}
+		}
+
 		if (unlink(oldpath) != 0)
 			ereport(FATAL,
 					(errcode_for_file_access(),
@@ -432,7 +495,7 @@ KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
 	 */
 	if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
 		XLogArchiveForceDone(xlogfname);
-	else
+	else if (!already_archived)
 		XLogArchiveNotify(xlogfname);
 
 	/*