Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

Started by Fujii Masaoover 13 years ago13 messages
#1Fujii Masao
masao.fujii@gmail.com
1 attachment(s)

On Tue, Jun 5, 2012 at 3:37 PM, Noah Misch <noah@leadboat.com> wrote:

On Fri, Mar 23, 2012 at 11:03:27PM +0900, Fujii Masao wrote:

(2) WAL files which were restored from the archive

In 9.1 or before, the restored WAL files don't remain after failover
because they are always restored onto the temporary filename
"RECOVERYXLOG". So the issue which I explain from now doesn't exist
in 9.1 or before.

In 9.2dev, as the result of supporting cascade replication,
an archived WAL file is restored onto correct file name so that
cascading walsender can send it to another standby. This restored

The documentation still says this:

WAL segments that cannot be found in the archive will be sought in pg_xlog/;
this allows use of recent un-archived segments. However, segments that are
available from the archive will be used in preference to files in
pg_xlog/. The system will not overwrite the existing contents of pg_xlog/
when retrieving archived files.

I gather the last sentence is now false?

Yes. Attached patch removes that sentence.

WAL file has neither .ready nor .done archive status file. After
failover, checkpoint checks the archive status file of the restored
WAL file to attempt to recycle it, finds that it has neither .ready
nor ,done, and creates .ready. Because of existence of .ready,
it will be archived again even though it obviously already exists in
the archival storage :(

To prevent a restored WAL file from being archived again, I think
that .done should be created whenever WAL file is successfully
restored (of course this should happen only when archive_mode is
enabled). Thought?

Your proposed fix makes sense, and I cannot think of any disadvantage.
Concerning only doing it when archive_mode=on, would there ever be a case
where a segment is restored under archive_mode=off, then the server restarted
with archive_mode=on and an archival attempted on that segment?

Yes, .done file should be created even if archive mode is not enabled.

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

Regards,

--
Fujii Masao

Attachments:

dont_archive_restored_walfile_v1.patchapplication/octet-stream; name=dont_archive_restored_walfile_v1.patchDownload
*** a/doc/src/sgml/backup.sgml
--- b/doc/src/sgml/backup.sgml
***************
*** 1071,1079 **** restore_command = 'cp /mnt/server/archivedir/%f %p'
      WAL segments that cannot be found in the archive will be sought in
      <filename>pg_xlog/</>; this allows use of recent un-archived segments.
      However, segments that are available from the archive will be used in
!     preference to files in <filename>pg_xlog/</>.  The system will not
!     overwrite the existing contents of <filename>pg_xlog/</> when retrieving
!     archived files.
     </para>
  
     <para>
--- 1071,1077 ----
      WAL segments that cannot be found in the archive will be sought in
      <filename>pg_xlog/</>; this allows use of recent un-archived segments.
      However, segments that are available from the archive will be used in
!     preference to files in <filename>pg_xlog/</>.
     </para>
  
     <para>
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 605,612 **** typedef struct xl_restore_point
  } xl_restore_point;
  
  
! static void XLogArchiveNotify(const char *xlog);
  static void XLogArchiveNotifySeg(XLogSegNo segno);
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
--- 605,613 ----
  } xl_restore_point;
  
  
! static void XLogArchiveNotify(const char *xlog, bool done);
  static void XLogArchiveNotifySeg(XLogSegNo segno);
+ static void XLogArchiveForceDone(const char *xlog);
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
***************
*** 1288,1302 **** XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
   * by the archiver, e.g. we write 0000000100000001000000C6.ready
   * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
   * then when complete, rename it to 0000000100000001000000C6.done
   */
  static void
! XLogArchiveNotify(const char *xlog)
  {
  	char		archiveStatusPath[MAXPGPATH];
  	FILE	   *fd;
  
! 	/* insert an otherwise empty file called <XLOG>.ready */
! 	StatusFilePath(archiveStatusPath, xlog, ".ready");
  	fd = AllocateFile(archiveStatusPath, "w");
  	if (fd == NULL)
  	{
--- 1289,1305 ----
   * by the archiver, e.g. we write 0000000100000001000000C6.ready
   * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
   * then when complete, rename it to 0000000100000001000000C6.done
+  *
+  * If done is true, create <XLOG>.done file. Otherwise, <XLOG>.ready.
   */
  static void
! XLogArchiveNotify(const char *xlog, bool done)
  {
  	char		archiveStatusPath[MAXPGPATH];
  	FILE	   *fd;
  
! 	/* insert an otherwise empty file called <XLOG>.ready or .done */
! 	StatusFilePath(archiveStatusPath, xlog, done ? ".done" : ".ready");
  	fd = AllocateFile(archiveStatusPath, "w");
  	if (fd == NULL)
  	{
***************
*** 1315,1327 **** XLogArchiveNotify(const char *xlog)
  		return;
  	}
  
! 	/* Notify archiver that it's got something to do */
! 	if (IsUnderPostmaster)
  		SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
  }
  
  /*
   * Convenience routine to notify using segment number representation of filename
   */
  static void
  XLogArchiveNotifySeg(XLogSegNo segno)
--- 1318,1332 ----
  		return;
  	}
  
! 	/* Notify archiver that it's got something to do if .ready has been created */
! 	if (IsUnderPostmaster && !done)
  		SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
  }
  
  /*
   * Convenience routine to notify using segment number representation of filename
+  *
+  * This always creates <XLOG>.ready.
   */
  static void
  XLogArchiveNotifySeg(XLogSegNo segno)
***************
*** 1329,1335 **** XLogArchiveNotifySeg(XLogSegNo segno)
  	char		xlog[MAXFNAMELEN];
  
  	XLogFileName(xlog, ThisTimeLineID, segno);
! 	XLogArchiveNotify(xlog);
  }
  
  /*
--- 1334,1376 ----
  	char		xlog[MAXFNAMELEN];
  
  	XLogFileName(xlog, ThisTimeLineID, segno);
! 	XLogArchiveNotify(xlog, false);
! }
! 
! /*
!  * 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.
!  */
! static void
! XLogArchiveForceDone(const char *xlog)
! {
! 	char		archiveReady[MAXPGPATH];
! 	char		archiveDone[MAXPGPATH];
! 	struct stat stat_buf;
! 
! 	/* 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)
! 	{
! 		if (rename(archiveReady, archiveDone) < 0)
! 			ereport(WARNING,
! 					(errcode_for_file_access(),
! 					 errmsg("could not rename file \"%s\" to \"%s\": %m",
! 							archiveReady, archiveDone)));
! 
! 		return;
! 	}
! 
! 	/* Create .done if neither .ready nor .done exists */
! 	XLogArchiveNotify(xlog, true);
  }
  
  /*
***************
*** 1372,1378 **** XLogArchiveCheckDone(const char *xlog)
  		return true;
  
  	/* Retry creation of the .ready file */
! 	XLogArchiveNotify(xlog);
  	return false;
  }
  
--- 1413,1419 ----
  		return true;
  
  	/* Retry creation of the .ready file */
! 	XLogArchiveNotify(xlog, false);
  	return false;
  }
  
***************
*** 2806,2811 **** XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
--- 2847,2858 ----
  							path, xlogfpath)));
  
  		/*
+ 		 * Create .done file forcibly to prevent the restored segment from
+ 		 * being archived again later.
+ 		 */
+ 		XLogArchiveForceDone(xlogfname);
+ 
+ 		/*
  		 * If the existing segment was replaced, since walsenders might have
  		 * it open, request them to reload a currently-open segment.
  		 */
***************
*** 4669,4675 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
  
  	/* The history file can be archived immediately. */
  	TLHistoryFileName(histfname, newTLI);
! 	XLogArchiveNotify(histfname);
  }
  
  /*
--- 4716,4722 ----
  
  	/* The history file can be archived immediately. */
  	TLHistoryFileName(histfname, newTLI);
! 	XLogArchiveNotify(histfname, false);
  }
  
  /*
***************
*** 5611,5617 **** exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
  		if (XLogArchivingActive())
  		{
  			XLogFileName(xlogpath, endTLI, endLogSegNo);
! 			XLogArchiveNotify(xlogpath);
  		}
  	}
  
--- 5658,5664 ----
  		if (XLogArchivingActive())
  		{
  			XLogFileName(xlogpath, endTLI, endLogSegNo);
! 			XLogArchiveNotify(xlogpath, false);
  		}
  	}
  
#2Fujii Masao
masao.fujii@gmail.com
In reply to: Fujii Masao (#1)
1 attachment(s)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Mon, Jul 30, 2012 at 12:01 AM, Fujii Masao <masao.fujii@gmail.com> wrote:

On Tue, Jun 5, 2012 at 3:37 PM, Noah Misch <noah@leadboat.com> wrote:

On Fri, Mar 23, 2012 at 11:03:27PM +0900, Fujii Masao wrote:

(2) WAL files which were restored from the archive

In 9.1 or before, the restored WAL files don't remain after failover
because they are always restored onto the temporary filename
"RECOVERYXLOG". So the issue which I explain from now doesn't exist
in 9.1 or before.

In 9.2dev, as the result of supporting cascade replication,
an archived WAL file is restored onto correct file name so that
cascading walsender can send it to another standby. This restored

The documentation still says this:

WAL segments that cannot be found in the archive will be sought in pg_xlog/;
this allows use of recent un-archived segments. However, segments that are
available from the archive will be used in preference to files in
pg_xlog/. The system will not overwrite the existing contents of pg_xlog/
when retrieving archived files.

I gather the last sentence is now false?

Yes. Attached patch removes that sentence.

WAL file has neither .ready nor .done archive status file. After
failover, checkpoint checks the archive status file of the restored
WAL file to attempt to recycle it, finds that it has neither .ready
nor ,done, and creates .ready. Because of existence of .ready,
it will be archived again even though it obviously already exists in
the archival storage :(

To prevent a restored WAL file from being archived again, I think
that .done should be created whenever WAL file is successfully
restored (of course this should happen only when archive_mode is
enabled). Thought?

Your proposed fix makes sense, and I cannot think of any disadvantage.
Concerning only doing it when archive_mode=on, would there ever be a case
where a segment is restored under archive_mode=off, then the server restarted
with archive_mode=on and an archival attempted on that segment?

Yes, .done file should be created even if archive mode is not enabled.

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

This patch can be applied cleanly for HEAD, but not in REL9_2_STABLE.
So here is the patch for REL9_2_STABLE.

Regards,

--
Fujii Masao

Attachments:

dont_archive_restored_walfile_for_REL9_2_STABLE_v1.patchapplication/octet-stream; name=dont_archive_restored_walfile_for_REL9_2_STABLE_v1.patchDownload
*** a/doc/src/sgml/backup.sgml
--- b/doc/src/sgml/backup.sgml
***************
*** 1071,1079 **** restore_command = 'cp /mnt/server/archivedir/%f %p'
      WAL segments that cannot be found in the archive will be sought in
      <filename>pg_xlog/</>; this allows use of recent un-archived segments.
      However, segments that are available from the archive will be used in
!     preference to files in <filename>pg_xlog/</>.  The system will not
!     overwrite the existing contents of <filename>pg_xlog/</> when retrieving
!     archived files.
     </para>
  
     <para>
--- 1071,1077 ----
      WAL segments that cannot be found in the archive will be sought in
      <filename>pg_xlog/</>; this allows use of recent un-archived segments.
      However, segments that are available from the archive will be used in
!     preference to files in <filename>pg_xlog/</>.
     </para>
  
     <para>
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 610,617 **** typedef struct xl_restore_point
  } xl_restore_point;
  
  
! static void XLogArchiveNotify(const char *xlog);
  static void XLogArchiveNotifySeg(uint32 log, uint32 seg);
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
--- 610,618 ----
  } xl_restore_point;
  
  
! static void XLogArchiveNotify(const char *xlog, bool done);
  static void XLogArchiveNotifySeg(uint32 log, uint32 seg);
+ static void XLogArchiveForceDone(const char *xlog);
  static bool XLogArchiveCheckDone(const char *xlog);
  static bool XLogArchiveIsBusy(const char *xlog);
  static void XLogArchiveCleanup(const char *xlog);
***************
*** 1291,1305 **** XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
   * by the archiver, e.g. we write 0000000100000001000000C6.ready
   * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
   * then when complete, rename it to 0000000100000001000000C6.done
   */
  static void
! XLogArchiveNotify(const char *xlog)
  {
  	char		archiveStatusPath[MAXPGPATH];
  	FILE	   *fd;
  
! 	/* insert an otherwise empty file called <XLOG>.ready */
! 	StatusFilePath(archiveStatusPath, xlog, ".ready");
  	fd = AllocateFile(archiveStatusPath, "w");
  	if (fd == NULL)
  	{
--- 1292,1308 ----
   * by the archiver, e.g. we write 0000000100000001000000C6.ready
   * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
   * then when complete, rename it to 0000000100000001000000C6.done
+  *
+  * If done is true, create <XLOG>.done file. Otherwise, <XLOG>.ready.
   */
  static void
! XLogArchiveNotify(const char *xlog, bool done)
  {
  	char		archiveStatusPath[MAXPGPATH];
  	FILE	   *fd;
  
! 	/* insert an otherwise empty file called <XLOG>.ready or .done */
! 	StatusFilePath(archiveStatusPath, xlog, done ? ".done" : ".ready");
  	fd = AllocateFile(archiveStatusPath, "w");
  	if (fd == NULL)
  	{
***************
*** 1318,1330 **** XLogArchiveNotify(const char *xlog)
  		return;
  	}
  
! 	/* Notify archiver that it's got something to do */
! 	if (IsUnderPostmaster)
  		SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
  }
  
  /*
   * Convenience routine to notify using log/seg representation of filename
   */
  static void
  XLogArchiveNotifySeg(uint32 log, uint32 seg)
--- 1321,1335 ----
  		return;
  	}
  
! 	/* Notify archiver that it's got something to do if .ready has been created */
! 	if (IsUnderPostmaster && !done)
  		SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
  }
  
  /*
   * Convenience routine to notify using log/seg representation of filename
+  *
+  * This always creates <XLOG>.ready.
   */
  static void
  XLogArchiveNotifySeg(uint32 log, uint32 seg)
***************
*** 1332,1338 **** XLogArchiveNotifySeg(uint32 log, uint32 seg)
  	char		xlog[MAXFNAMELEN];
  
  	XLogFileName(xlog, ThisTimeLineID, log, seg);
! 	XLogArchiveNotify(xlog);
  }
  
  /*
--- 1337,1379 ----
  	char		xlog[MAXFNAMELEN];
  
  	XLogFileName(xlog, ThisTimeLineID, log, seg);
! 	XLogArchiveNotify(xlog, false);
! }
! 
! /*
!  * 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.
!  */
! static void
! XLogArchiveForceDone(const char *xlog)
! {
! 	char		archiveReady[MAXPGPATH];
! 	char		archiveDone[MAXPGPATH];
! 	struct stat stat_buf;
! 
! 	/* 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)
! 	{
! 		if (rename(archiveReady, archiveDone) < 0)
! 			ereport(WARNING,
! 					(errcode_for_file_access(),
! 					 errmsg("could not rename file \"%s\" to \"%s\": %m",
! 							archiveReady, archiveDone)));
! 
! 		return;
! 	}
! 
! 	/* Create .done if neither .ready nor .done exists */
! 	XLogArchiveNotify(xlog, true);
  }
  
  /*
***************
*** 1375,1381 **** XLogArchiveCheckDone(const char *xlog)
  		return true;
  
  	/* Retry creation of the .ready file */
! 	XLogArchiveNotify(xlog);
  	return false;
  }
  
--- 1416,1422 ----
  		return true;
  
  	/* Retry creation of the .ready file */
! 	XLogArchiveNotify(xlog, false);
  	return false;
  }
  
***************
*** 2810,2815 **** XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
--- 2851,2862 ----
  							path, xlogfpath)));
  
  		/*
+ 		 * Create .done file forcibly to prevent the restored segment from
+ 		 * being archived again later.
+ 		 */
+ 		XLogArchiveForceDone(xlogfname);
+ 
+ 		/*
  		 * If the existing segment was replaced, since walsenders might have
  		 * it open, request them to reload a currently-open segment.
  		 */
***************
*** 4649,4655 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
  
  	/* The history file can be archived immediately. */
  	TLHistoryFileName(histfname, newTLI);
! 	XLogArchiveNotify(histfname);
  }
  
  /*
--- 4696,4702 ----
  
  	/* The history file can be archived immediately. */
  	TLHistoryFileName(histfname, newTLI);
! 	XLogArchiveNotify(histfname, false);
  }
  
  /*
***************
*** 5596,5602 **** exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
  		if (XLogArchivingActive())
  		{
  			XLogFileName(xlogpath, endTLI, endLogId, endLogSeg);
! 			XLogArchiveNotify(xlogpath);
  		}
  	}
  
--- 5643,5649 ----
  		if (XLogArchivingActive())
  		{
  			XLogFileName(xlogpath, endTLI, endLogId, endLogSeg);
! 			XLogArchiveNotify(xlogpath, false);
  		}
  	}
  
#3Simon Riggs
simon@2ndQuadrant.com
In reply to: Fujii Masao (#1)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On 29 July 2012 16:01, Fujii Masao <masao.fujii@gmail.com> wrote:

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

The proposed patch works, for archiving only, but I don't like the
code. It's a partial refactoring of existing code.

I prefer to go for a full re-factoring version for HEAD, and a zero
refactoring version for 9.2 since we're deep into beta.

I've committed the simplified version for 9.2, as well as adding
support for streaming which you seem to have missed out.

Will look at the refactored version tomorrow.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#4Simon Riggs
simon@2ndquadrant.com
In reply to: Simon Riggs (#3)
1 attachment(s)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On 9 August 2012 00:08, Simon Riggs <simon@2ndquadrant.com> wrote:

Will look at the refactored version tomorrow.

Rather than implement the minimal patch onto HEAD, I've written a
refactored patch. [attached]
This fixes the bugs discussed here, though allows for multiple archive
statuses, rather than just two, as well as removing similar code.

We've talked about allowing file based replication to cascade, i.e.
having the archiver run on standby and to push files onwards from the
standby.

The way I'd like to do this is

If archiving active
* Allow archiver to run on standby
* When xlog file written on standby it sets archive_status to ".standby"
* When archiver runs it will execute archive_command when it sees a
status of ".ready" or it will execute standby_archive_command when it
sees a status of ".standby". In both cases it will set a status of
".done" when complete. It doesn't need to know whether promotion has
happened, or even when it happened, because the status of the xlog
files is clearly marked.

We can't use ".ready" to mean two things because then we'd be confused
how to handle files generated during standby but archived after
promotion has taken place. ".done" always means you can clean up the
xlog files now, in all cases.

You're welcome to complete the implementation using this patch, or
I'll do that when I get back from leave.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

refactor_archive_status.v1.patchapplication/octet-stream; name=refactor_archive_status.v1.patchDownload
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index efd0347..393315f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -605,7 +605,6 @@ typedef struct xl_restore_point
 } xl_restore_point;
 
 
-static void XLogArchiveNotify(const char *xlog);
 static void XLogArchiveNotifySeg(XLogSegNo segno);
 static bool XLogArchiveCheckDone(const char *xlog);
 static bool XLogArchiveIsBusy(const char *xlog);
@@ -1280,23 +1279,63 @@ XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
 }
 
 /*
- * XLogArchiveNotify
+ * XLogSetArchiveStatus
  *
- * Create an archive notification file
+ * Create an archive notification file with given archive status
  *
  * The name of the notification file is the message that will be picked up
  * by the archiver, e.g. we write 0000000100000001000000C6.ready
  * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6,
  * then when complete, rename it to 0000000100000001000000C6.done
  */
-static void
-XLogArchiveNotify(const char *xlog)
+void
+XLogSetArchiveStatus(const char *xlog, int archive_status)
 {
 	char		archiveStatusPath[MAXPGPATH];
+	struct stat stat_buf;
 	FILE	   *fd;
 
-	/* insert an otherwise empty file called <XLOG>.ready */
-	StatusFilePath(archiveStatusPath, xlog, ".ready");
+	switch (archive_status)
+	{
+		case XLOG_ARCHIVE_STATUS_READY:
+
+			/* If already marked READY then quick exit */
+			StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY);
+			if (stat(archiveStatusPath, &stat_buf) == 0)
+				return;
+
+			break;
+
+		case XLOG_ARCHIVE_STATUS_DONE:
+
+			/* If marked READY then rename to DONE */
+			StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY);
+			if (stat(archiveStatusPath, &stat_buf) == 0)
+			{
+				char	archiveStatusDone[MAXPGPATH];
+
+				StatusFilePath(archiveStatusDone, xlog, XLOG_ARCHIVE_STATUS_DONE);
+
+				if (rename(archiveStatusPath, archiveStatusDone) < 0)
+					ereport(WARNING,
+							(errcode_for_file_access(),
+							 errmsg("could not rename file \"%s\" to \"%s\": %m",
+									archiveStatusPath, archiveStatusDone)));
+				return;
+			}
+
+			/* If already marked DONE then exit */
+			StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
+			if (stat(archiveStatusPath, &stat_buf) == 0)
+				return;
+
+			break;
+
+		default:
+			elog(ERROR, "invalud archive status");
+	}
+
+	/* insert an otherwise empty file with prefix that indicates archive_status */
 	fd = AllocateFile(archiveStatusPath, "w");
 	if (fd == NULL)
 	{
@@ -1315,13 +1354,15 @@ XLogArchiveNotify(const char *xlog)
 		return;
 	}
 
-	/* Notify archiver that it's got something to do */
-	if (IsUnderPostmaster)
+	/* Notify archiver that it's got something to do if .ready has been created */
+	if (IsUnderPostmaster && archive_status == XLOG_ARCHIVE_STATUS_READY)
 		SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER);
 }
 
 /*
  * Convenience routine to notify using segment number representation of filename
+ *
+ * This always creates XLOG_ARCHIVE_STATUS_READY
  */
 static void
 XLogArchiveNotifySeg(XLogSegNo segno)
@@ -1329,7 +1370,7 @@ XLogArchiveNotifySeg(XLogSegNo segno)
 	char		xlog[MAXFNAMELEN];
 
 	XLogFileName(xlog, ThisTimeLineID, segno);
-	XLogArchiveNotify(xlog);
+	XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_READY);
 }
 
 /*
@@ -1357,22 +1398,22 @@ XLogArchiveCheckDone(const char *xlog)
 		return true;
 
 	/* First check for .done --- this means archiver is done with it */
-	StatusFilePath(archiveStatusPath, xlog, ".done");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return true;
 
 	/* check for .ready --- this means archiver is still busy with it */
-	StatusFilePath(archiveStatusPath, xlog, ".ready");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return false;
 
 	/* Race condition --- maybe archiver just finished, so recheck */
-	StatusFilePath(archiveStatusPath, xlog, ".done");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return true;
 
 	/* Retry creation of the .ready file */
-	XLogArchiveNotify(xlog);
+	XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_READY);
 	return false;
 }
 
@@ -1393,17 +1434,17 @@ XLogArchiveIsBusy(const char *xlog)
 	struct stat stat_buf;
 
 	/* First check for .done --- this means archiver is done with it */
-	StatusFilePath(archiveStatusPath, xlog, ".done");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return false;
 
 	/* check for .ready --- this means archiver is still busy with it */
-	StatusFilePath(archiveStatusPath, xlog, ".ready");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return true;
 
 	/* Race condition --- maybe archiver just finished, so recheck */
-	StatusFilePath(archiveStatusPath, xlog, ".done");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
 	if (stat(archiveStatusPath, &stat_buf) == 0)
 		return false;
 
@@ -1431,12 +1472,12 @@ XLogArchiveCleanup(const char *xlog)
 	char		archiveStatusPath[MAXPGPATH];
 
 	/* Remove the .done file */
-	StatusFilePath(archiveStatusPath, xlog, ".done");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE);
 	unlink(archiveStatusPath);
 	/* should we complain about failure? */
 
 	/* Remove the .ready file if present --- normally it shouldn't be */
-	StatusFilePath(archiveStatusPath, xlog, ".ready");
+	StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY);
 	unlink(archiveStatusPath);
 	/* should we complain about failure? */
 }
@@ -2806,6 +2847,12 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 							path, xlogfpath)));
 
 		/*
+		 * Create .done file forcibly to prevent the restored segment from
+		 * being archived again later.
+		 */
+		XLogSetArchiveStatus(xlogfname, XLOG_ARCHIVE_STATUS_DONE);
+
+		/*
 		 * If the existing segment was replaced, since walsenders might have
 		 * it open, request them to reload a currently-open segment.
 		 */
@@ -3573,7 +3620,7 @@ ValidateXLOGDirectoryStructure(void)
 
 /*
  * Remove previous backup history files.  This also retries creation of
- * .ready files for any backup history files for which XLogArchiveNotify
+ * .ready files for any backup history files for which XLogSetArchiveStatus
  * failed earlier.
  */
 static void
@@ -4669,7 +4716,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 
 	/* The history file can be archived immediately. */
 	TLHistoryFileName(histfname, newTLI);
-	XLogArchiveNotify(histfname);
+	XLogSetArchiveStatus(histfname, XLOG_ARCHIVE_STATUS_READY);
 }
 
 /*
@@ -5611,7 +5658,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 		if (XLogArchivingActive())
 		{
 			XLogFileName(xlogpath, endTLI, endLogSegNo);
-			XLogArchiveNotify(xlogpath);
+			XLogSetArchiveStatus(xlogpath, XLOG_ARCHIVE_STATUS_READY);
 		}
 	}
 
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index d5d8be0..1a51e17 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -111,7 +111,6 @@ static void pgarch_MainLoop(void);
 static void pgarch_ArchiverCopyLoop(void);
 static bool pgarch_archiveXlog(char *xlog);
 static bool pgarch_readyXlog(char *xlog);
-static void pgarch_archiveDone(char *xlog);
 
 
 /* ------------------------------------------------------------
@@ -492,7 +491,7 @@ pgarch_ArchiverCopyLoop(void)
 			if (pgarch_archiveXlog(xlog))
 			{
 				/* successful */
-				pgarch_archiveDone(xlog);
+				XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_DONE);
 				break;			/* out of inner retry loop */
 			}
 			else
@@ -730,26 +729,3 @@ pgarch_readyXlog(char *xlog)
 	}
 	return found;
 }
-
-/*
- * pgarch_archiveDone
- *
- * Emit notification that an xlog file has been successfully archived.
- * We do this by renaming the status file from NNN.ready to NNN.done.
- * Eventually, a checkpoint process will notice this and delete both the
- * NNN.done file and the xlog file itself.
- */
-static void
-pgarch_archiveDone(char *xlog)
-{
-	char		rlogready[MAXPGPATH];
-	char		rlogdone[MAXPGPATH];
-
-	StatusFilePath(rlogready, xlog, ".ready");
-	StatusFilePath(rlogdone, xlog, ".done");
-	if (rename(rlogready, rlogdone) < 0)
-		ereport(WARNING,
-				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						rlogready, rlogdone)));
-}
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b0a8b19..9d689c2 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -505,6 +505,13 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
 							(errcode_for_file_access(),
 							 errmsg("could not close log segment %s: %m",
 									XLogFileNameP(recvFileTLI, recvSegNo))));
+
+				/*
+				 * Create .done file forcibly to prevent the restored segment from
+				 * being archived again later.
+				 */
+				XLogSetArchiveStatus(XLogFileNameP(recvFileTLI, recvSegNo),
+										XLOG_ARCHIVE_STATUS_DONE);
 			}
 			recvFile = -1;
 
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index b5bfb7b..78849ce 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -192,8 +192,14 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
 #define TLHistoryFilePath(path, tli)	\
 	snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli)
 
-#define StatusFilePath(path, xlog, suffix)	\
-	snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix)
+#define XLOG_ARCHIVE_STATUS_INVALID	0
+#define XLOG_ARCHIVE_STATUS_READY	1
+#define XLOG_ARCHIVE_STATUS_DONE	2
+
+#define StatusFilePath(path, xlog, archive_status)	\
+	snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, \
+		(archive_status == XLOG_ARCHIVE_STATUS_READY ? ".ready" : ".done"))
+
 
 #define BackupHistoryFileName(fname, tli, logSegNo, offset) \
 	snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \
@@ -230,6 +236,11 @@ extern pg_time_t GetLastSegSwitchTime(void);
 extern XLogRecPtr RequestXLogSwitch(void);
 
 /*
+ * Exported to support xlog archive status setting from WALReceiver/Archiver
+ */
+extern void XLogSetArchiveStatus(const char *xlog, int archive_status);
+
+/*
  * These aren't in xlog.h because I'd rather not include fmgr.h there.
  */
 extern Datum pg_start_backup(PG_FUNCTION_ARGS);
#5Fujii Masao
masao.fujii@gmail.com
In reply to: Simon Riggs (#3)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Thu, Aug 9, 2012 at 8:08 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 July 2012 16:01, Fujii Masao <masao.fujii@gmail.com> wrote:

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

The proposed patch works, for archiving only, but I don't like the
code. It's a partial refactoring of existing code.

I prefer to go for a full re-factoring version for HEAD, and a zero
refactoring version for 9.2 since we're deep into beta.

Sounds reasonable.

I've committed the simplified version for 9.2, as well as adding
support for streaming which you seem to have missed out.

If the streaming case really must be covered, the fix should be backported to
9.1 and 9.0? Because there is the same "problem" in those versions.

But I'm not sure if this fix is right thing to do. I didn't add any code to the
streaming case because the current behavior exists since 9.0 and AFAIR
we've not received the complaints about the behavior. So ISTM changing
that behavior is debatable and looks like 9.3 item rather than 9.2.

Regards,

--
Fujii Masao

#6Fujii Masao
masao.fujii@gmail.com
In reply to: Simon Riggs (#4)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Thu, Aug 9, 2012 at 11:24 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 9 August 2012 00:08, Simon Riggs <simon@2ndquadrant.com> wrote:

Will look at the refactored version tomorrow.

Rather than implement the minimal patch onto HEAD, I've written a
refactored patch. [attached]
This fixes the bugs discussed here, though allows for multiple archive
statuses, rather than just two, as well as removing similar code.

We've talked about allowing file based replication to cascade, i.e.
having the archiver run on standby and to push files onwards from the
standby.

The way I'd like to do this is

If archiving active
* Allow archiver to run on standby
* When xlog file written on standby it sets archive_status to ".standby"
* When archiver runs it will execute archive_command when it sees a
status of ".ready" or it will execute standby_archive_command when it
sees a status of ".standby". In both cases it will set a status of
".done" when complete. It doesn't need to know whether promotion has
happened, or even when it happened, because the status of the xlog
files is clearly marked.

We can't use ".ready" to mean two things because then we'd be confused
how to handle files generated during standby but archived after
promotion has taken place. ".done" always means you can clean up the
xlog files now, in all cases.

Sounds good to me.

Regards,

--
Fujii Masao

#7Noname
armin.schoeffmann@aegaeon.de
In reply to: Fujii Masao (#5)
Out of office

Dear sender,
I'm away from the office till 19th of August. In the meantime, please contact my colleague Alfred Vater at alfred.vater@aegaeon.de

#8Simon Riggs
simon@2ndQuadrant.com
In reply to: Fujii Masao (#5)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On 10 August 2012 18:19, Fujii Masao <masao.fujii@gmail.com> wrote:

I've committed the simplified version for 9.2, as well as adding
support for streaming which you seem to have missed out.

If the streaming case really must be covered, the fix should be backported to
9.1 and 9.0? Because there is the same "problem" in those versions.

True

But I'm not sure if this fix is right thing to do. I didn't add any code to the
streaming case because the current behavior exists since 9.0 and AFAIR
we've not received the complaints about the behavior. So ISTM changing
that behavior is debatable and looks like 9.3 item rather than 9.2.

If its a bug with archiving, then why is it not a bug with streaming?

What if you are using archiving and streaming, what then? There isn't
any way of telling the difference between them.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#9Fujii Masao
masao.fujii@gmail.com
In reply to: Fujii Masao (#5)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Sat, Aug 11, 2012 at 2:19 AM, Fujii Masao <masao.fujii@gmail.com> wrote:

On Thu, Aug 9, 2012 at 8:08 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 July 2012 16:01, Fujii Masao <masao.fujii@gmail.com> wrote:

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

The proposed patch works, for archiving only, but I don't like the
code. It's a partial refactoring of existing code.

I prefer to go for a full re-factoring version for HEAD, and a zero
refactoring version for 9.2 since we're deep into beta.

Isn't it time to push the full re-factoring version to HEAD? If there is no
such version yet, what about pushing the zero refactoring version for now?

Regards,

--
Fujii Masao

#10Simon Riggs
simon@2ndQuadrant.com
In reply to: Fujii Masao (#9)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On 2 October 2012 19:06, Fujii Masao <masao.fujii@gmail.com> wrote:

On Sat, Aug 11, 2012 at 2:19 AM, Fujii Masao <masao.fujii@gmail.com> wrote:

On Thu, Aug 9, 2012 at 8:08 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 July 2012 16:01, Fujii Masao <masao.fujii@gmail.com> wrote:

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

The proposed patch works, for archiving only, but I don't like the
code. It's a partial refactoring of existing code.

I prefer to go for a full re-factoring version for HEAD, and a zero
refactoring version for 9.2 since we're deep into beta.

Isn't it time to push the full re-factoring version to HEAD? If there is no
such version yet, what about pushing the zero refactoring version for now?

If you send a rebased patch, I'll review, but its not high on my radar
right now unless you can explain why it should be higher.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#11Fujii Masao
masao.fujii@gmail.com
In reply to: Simon Riggs (#10)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Wed, Oct 3, 2012 at 3:11 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 2 October 2012 19:06, Fujii Masao <masao.fujii@gmail.com> wrote:

On Sat, Aug 11, 2012 at 2:19 AM, Fujii Masao <masao.fujii@gmail.com> wrote:

On Thu, Aug 9, 2012 at 8:08 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 July 2012 16:01, Fujii Masao <masao.fujii@gmail.com> wrote:

Attached patch changes the startup process so that it creates .done file
whenever WAL file is successfully restored, whether archive mode is
enabled or not. The restored WAL files will not be archived again because
of .done file.

The proposed patch works, for archiving only, but I don't like the
code. It's a partial refactoring of existing code.

I prefer to go for a full re-factoring version for HEAD, and a zero
refactoring version for 9.2 since we're deep into beta.

Isn't it time to push the full re-factoring version to HEAD? If there is no
such version yet, what about pushing the zero refactoring version for now?

If you send a rebased patch, I'll review,

Okay. Will do. The patch needs to be revised to correspond with the recent
split of xlog.c.

but its not high on my radar
right now unless you can explain why it should be higher.

It may not be high, but I'm just worried that we are likely to forget to
apply that change into HEAD if we postpone it furthermore.

Regards,

--
Fujii Masao

#12Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Fujii Masao (#11)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On 02.10.2012 21:20, Fujii Masao wrote:

On Wed, Oct 3, 2012 at 3:11 AM, Simon Riggs<simon@2ndquadrant.com> wrote:

but its not high on my radar
right now unless you can explain why it should be higher.

It may not be high, but I'm just worried that we are likely to forget to
apply that change into HEAD if we postpone it furthermore.

Ping? I haven't been paying much attention to this, but please commit
the 9.2 fix to HEAD. This just caused a small merge conflict when I
tried to backport (or rather, forward-port) a patch. We do more changes
to HEAD later.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Fujii Masao
masao.fujii@gmail.com
In reply to: Heikki Linnakangas (#12)
1 attachment(s)
Re: Prevent restored WAL files from being archived again Re: Unnecessary WAL archiving after failover

On Sun, Dec 30, 2012 at 6:07 AM, Heikki Linnakangas
<hlinnakangas@vmware.com> wrote:

On 02.10.2012 21:20, Fujii Masao wrote:

On Wed, Oct 3, 2012 at 3:11 AM, Simon Riggs<simon@2ndquadrant.com> wrote:

but its not high on my radar

right now unless you can explain why it should be higher.

It may not be high, but I'm just worried that we are likely to forget to
apply that change into HEAD if we postpone it furthermore.

Ping? I haven't been paying much attention to this, but please commit the
9.2 fix to HEAD. This just caused a small merge conflict when I tried to
backport (or rather, forward-port) a patch. We do more changes to HEAD
later.

Sorry for the late. I attached the patch for HEAD. Since I've not understood
completely the recent change related to handling of the timeline yet, the patch
might treat with the timeline wrongly. I'm not sure if this patch has something
to do with the recent change, though. I appreciate it if you review carefully
the patch.

Regards,

--
Fujii Masao

Attachments:

dont_archive_restored_walfile_v2.patchapplication/octet-stream; name=dont_archive_restored_walfile_v2.patchDownload
*** a/src/backend/access/transam/xlogarchive.c
--- b/src/backend/access/transam/xlogarchive.c
***************
*** 474,479 **** KeepFileRestoredFromArchive(char *path, char *xlogfname)
--- 474,485 ----
  						path, xlogfpath)));
  
  	/*
+ 	 * Create .done file forcibly to prevent the restored segment from
+ 	 * being archived again later.
+ 	 */
+ 	XLogArchiveForceDone(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
***************
*** 545,550 **** XLogArchiveNotifySeg(XLogSegNo segno)
--- 551,609 ----
  }
  
  /*
+  * 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)
+ 	{
+ 		if (rename(archiveReady, archiveDone) < 0)
+ 			ereport(WARNING,
+ 					(errcode_for_file_access(),
+ 					 errmsg("could not rename file \"%s\" to \"%s\": %m",
+ 							archiveReady, archiveDone)));
+ 
+ 		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
   *
   * This is called when we are ready to delete or recycle an old XLOG segment
*** a/src/backend/replication/walreceiver.c
--- b/src/backend/replication/walreceiver.c
***************
*** 83,89 **** walrcv_disconnect_type walrcv_disconnect = NULL;
  /*
   * These variables are used similarly to openLogFile/SegNo/Off,
   * but for walreceiver to write the XLOG. recvFileTLI is the TimeLineID
!  * corresponding the filename of recvFile, used for error messages.
   */
  static int	recvFile = -1;
  static TimeLineID	recvFileTLI = 0;
--- 83,89 ----
  /*
   * These variables are used similarly to openLogFile/SegNo/Off,
   * but for walreceiver to write the XLOG. recvFileTLI is the TimeLineID
!  * corresponding the filename of recvFile.
   */
  static int	recvFile = -1;
  static TimeLineID	recvFileTLI = 0;
***************
*** 528,539 **** WalReceiverMain(void)
--- 528,548 ----
  		 */
  		if (recvFile >= 0)
  		{
+ 			char		xlogfname[MAXFNAMELEN];
+ 
  			XLogWalRcvFlush(false);
  			if (close(recvFile) != 0)
  				ereport(PANIC,
  						(errcode_for_file_access(),
  						 errmsg("could not close log segment %s: %m",
  								XLogFileNameP(recvFileTLI, recvSegNo))));
+ 
+ 			/*
+ 			 * Create .done file forcibly to prevent the streamed segment from
+ 			 * being archived later.
+ 			 */
+ 			XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+ 			XLogArchiveForceDone(xlogfname);
  		}
  		recvFile = -1;
  
***************
*** 865,870 **** XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
--- 874,881 ----
  			 */
  			if (recvFile >= 0)
  			{
+ 				char		xlogfname[MAXFNAMELEN];
+ 
  				XLogWalRcvFlush(false);
  
  				/*
***************
*** 877,882 **** XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
--- 888,900 ----
  							(errcode_for_file_access(),
  							 errmsg("could not close log segment %s: %m",
  									XLogFileNameP(recvFileTLI, recvSegNo))));
+ 
+ 				/*
+ 				 * Create .done file forcibly to prevent the streamed segment from
+ 				 * being archived later.
+ 				 */
+ 				XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+ 				XLogArchiveForceDone(xlogfname);
  			}
  			recvFile = -1;
  
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 278,283 **** extern void ExecuteRecoveryCommand(char *command, char *commandName,
--- 278,284 ----
  extern void KeepFileRestoredFromArchive(char  *path, char *xlogfname);
  extern void XLogArchiveNotify(const char *xlog);
  extern void XLogArchiveNotifySeg(XLogSegNo segno);
+ extern void XLogArchiveForceDone(const char *xlog);
  extern bool XLogArchiveCheckDone(const char *xlog);
  extern bool XLogArchiveIsBusy(const char *xlog);
  extern void XLogArchiveCleanup(const char *xlog);