@@ -3020,24 +3020,22 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
30203020}
30213021
30223022/*
3023- * Create a new XLOG file segment by copying a pre-existing one .
3023+ * Copy a WAL segment file in pg_xlog directory .
30243024 *
3025- * destsegno: identify segment to be created.
3025+ * dstfname destination filename
3026+ * srcfname source filename
3027+ * upto how much of the source file to copy? (the rest is filled with
3028+ * zeros)
30263029 *
3027- * srcTLI, srclog, srcseg: identify segment to be copied (could be from
3028- * a different timeline)
3030+ * If dstfname is not given, the file is created with a temporary filename,
3031+ * which is returned. Both filenames are relative to the pg_xlog directory.
30293032 *
3030- * upto: how much of the source file to copy? (the rest is filled with zeros)
3031- *
3032- * Currently this is only used during recovery, and so there are no locking
3033- * considerations. But we should be just as tense as XLogFileInit to avoid
3034- * emplacing a bogus file.
3033+ * NB: Any existing file with the same name will be overwritten!
30353034 */
3036- static void
3037- XLogFileCopy (XLogSegNo destsegno , TimeLineID srcTLI , XLogSegNo srcsegno ,
3038- int upto )
3035+ static char *
3036+ XLogFileCopy (char * dstfname , char * srcfname , int upto )
30393037{
3040- char path [MAXPGPATH ];
3038+ char srcpath [MAXPGPATH ];
30413039 char tmppath [MAXPGPATH ];
30423040 char buffer [XLOG_BLCKSZ ];
30433041 int srcfd ;
@@ -3047,12 +3045,12 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
30473045 /*
30483046 * Open the source file
30493047 */
3050- XLogFilePath ( path , srcTLI , srcsegno );
3051- srcfd = OpenTransientFile (path , O_RDONLY | PG_BINARY , 0 );
3048+ snprintf ( srcpath , MAXPGPATH , XLOGDIR "/%s" , srcfname );
3049+ srcfd = OpenTransientFile (srcpath , O_RDONLY | PG_BINARY , 0 );
30523050 if (srcfd < 0 )
30533051 ereport (ERROR ,
30543052 (errcode_for_file_access (),
3055- errmsg ("could not open file \"%s\": %m" , path )));
3053+ errmsg ("could not open file \"%s\": %m" , srcpath )));
30563054
30573055 /*
30583056 * Copy into a temp file name.
@@ -3094,10 +3092,12 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
30943092 if (errno != 0 )
30953093 ereport (ERROR ,
30963094 (errcode_for_file_access (),
3097- errmsg ("could not read file \"%s\": %m" , path )));
3095+ errmsg ("could not read file \"%s\": %m" ,
3096+ srcpath )));
30983097 else
30993098 ereport (ERROR ,
3100- (errmsg ("not enough data in file \"%s\"" , path )));
3099+ (errmsg ("not enough data in file \"%s\"" ,
3100+ srcpath )));
31013101 }
31023102 }
31033103 errno = 0 ;
@@ -3131,10 +3131,24 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
31313131 CloseTransientFile (srcfd );
31323132
31333133 /*
3134- * Now move the segment into place with its final name.
3134+ * Now move the segment into place with its final name. (Or just return
3135+ * the path to the file we created, if the caller wants to handle the
3136+ * rest on its own.)
31353137 */
3136- if (!InstallXLogFileSegment (& destsegno , tmppath , false, 0 , false))
3137- elog (ERROR , "InstallXLogFileSegment should not have failed" );
3138+ if (dstfname )
3139+ {
3140+ char dstpath [MAXPGPATH ];
3141+
3142+ snprintf (dstpath , MAXPGPATH , XLOGDIR "/%s" , dstfname );
3143+ if (rename (tmppath , dstpath ) < 0 )
3144+ ereport (ERROR ,
3145+ (errcode_for_file_access (),
3146+ errmsg ("could not rename file \"%s\" to \"%s\": %m" ,
3147+ tmppath , dstpath )));
3148+ return NULL ;
3149+ }
3150+ else
3151+ return pstrdup (tmppath );
31383152}
31393153
31403154/*
@@ -3577,7 +3591,8 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
35773591 while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
35783592 {
35793593 /* Ignore files that are not XLOG segments */
3580- if (!IsXLogFileName (xlde -> d_name ))
3594+ if (!IsXLogFileName (xlde -> d_name ) &&
3595+ !IsPartialXLogFileName (xlde -> d_name ))
35813596 continue ;
35823597
35833598 /*
@@ -5189,25 +5204,79 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
51895204 * of the old timeline up to the switch point, to the starting WAL segment
51905205 * on the new timeline.
51915206 *
5192- * Notify the archiver that the last WAL segment of the old timeline is
5193- * ready to copy to archival storage if its .done file doesn't exist
5194- * (e.g., if it's the restored WAL file, it's expected to have .done file).
5195- * Otherwise, it is not archived for a while.
5207+ * What to do with the partial segment on the old timeline? If we don't
5208+ * archive it, and the server that created the WAL never archives it
5209+ * either (e.g. because it was hit by a meteor), it will never make it to
5210+ * the archive. That's OK from our point of view, because the new segment
5211+ * that we created with the new TLI contains all the WAL from the old
5212+ * timeline up to the switch point. But if you later try to do PITR to the
5213+ * "missing" WAL on the old timeline, recovery won't find it in the
5214+ * archive. It's physically present in the new file with new TLI, but
5215+ * recovery won't look there when it's recovering to the older timeline.
5216+ * On the other hand, if we archive the partial segment, and the original
5217+ * server on that timeline is still running and archives the completed
5218+ * version of the same segment later, it will fail. (We used to do that in
5219+ * 9.4 and below, and it caused such problems).
5220+ *
5221+ * As a compromise, we archive the last segment with the .partial suffix.
5222+ * Archive recovery will never try to read .partial segments, so they will
5223+ * normally go unused. But in the odd PITR case, the administrator can
5224+ * copy them manually to the pg_xlog directory (removing the suffix). They
5225+ * can be useful in debugging, too.
5226+ *
5227+ * If a .done file already exists for the old timeline, however, there is
5228+ * already a complete copy of the file in the archive, and there is no
5229+ * need to archive the partial one. (In particular, if it was restored
5230+ * from the archive to begin with, it's expected to have .done file).
51965231 */
51975232 if (endLogSegNo == startLogSegNo )
51985233 {
5199- XLogFileCopy (startLogSegNo , endTLI , endLogSegNo ,
5200- endOfLog % XLOG_SEG_SIZE );
5234+ char * tmpfname ;
5235+
5236+ XLogFileName (xlogfname , endTLI , endLogSegNo );
5237+
5238+ /*
5239+ * Make a copy of the file on the new timeline.
5240+ *
5241+ * Writing WAL isn't allowed yet, so there are no locking
5242+ * considerations. But we should be just as tense as XLogFileInit to
5243+ * avoid emplacing a bogus file.
5244+ */
5245+ tmpfname = XLogFileCopy (NULL , xlogfname , endOfLog % XLOG_SEG_SIZE );
5246+ if (!InstallXLogFileSegment (& endLogSegNo , tmpfname , false, 0 , false))
5247+ elog (ERROR , "InstallXLogFileSegment should not have failed" );
52015248
5202- /* Create .ready file only when neither .ready nor .done files exist */
5203- if (XLogArchivingActive ())
5249+ /*
5250+ * Make a .partial copy for the archive (unless the original file was
5251+ * already archived)
5252+ */
5253+ if (XLogArchivingActive () && XLogArchiveIsBusy (xlogfname ))
52045254 {
5205- XLogFileName (xlogfname , endTLI , endLogSegNo );
5206- XLogArchiveCheckDone (xlogfname );
5255+ char partialfname [MAXFNAMELEN ];
5256+
5257+ snprintf (partialfname , MAXFNAMELEN , "%s.partial" , xlogfname );
5258+
5259+ /* Make sure there's no .done or .ready file for it. */
5260+ XLogArchiveCleanup (partialfname );
5261+
5262+ /*
5263+ * We copy the whole segment, not just upto the switch point.
5264+ * The portion after the switch point might be garbage, but it
5265+ * might also be valid WAL, if we stopped recovery at user's
5266+ * request before reaching the end. Better to preserve the
5267+ * file as it is, garbage and all, than lose the evidence if
5268+ * something goes wrong.
5269+ */
5270+ (void ) XLogFileCopy (partialfname , xlogfname , XLOG_SEG_SIZE );
5271+ XLogArchiveNotify (partialfname );
52075272 }
52085273 }
52095274 else
52105275 {
5276+ /*
5277+ * The switch happened at a segment boundary, so just create the next
5278+ * segment on the new timeline.
5279+ */
52115280 bool use_existent = true;
52125281 int fd ;
52135282
0 commit comments