@@ -564,6 +564,7 @@ static void XLogArchiveNotify(const char *xlog);
564564static void XLogArchiveNotifySeg (uint32 log ,uint32 seg );
565565static bool XLogArchiveCheckDone (const char * xlog );
566566static bool XLogArchiveIsBusy (const char * xlog );
567+ extern bool XLogArchiveIsReady (const char * xlog );
567568static void XLogArchiveCleanup (const char * xlog );
568569static void readRecoveryCommandFile (void );
569570static void exitArchiveRecovery (TimeLineID endTLI ,
@@ -598,6 +599,8 @@ static void ExecuteRecoveryCommand(char *command, char *commandName,
598599bool failOnerror );
599600static void PreallocXlogFiles (XLogRecPtr endptr );
600601static void RemoveOldXlogFiles (uint32 log ,uint32 seg ,XLogRecPtr endptr );
602+ static void RemoveXlogFile (const char * segname ,XLogRecPtr endptr );
603+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint ,TimeLineID newTLI );
601604static void UpdateLastRemovedPtr (char * filename );
602605static void ValidateXLOGDirectoryStructure (void );
603606static void CleanupBackupHistory (void );
@@ -1405,6 +1408,25 @@ XLogArchiveIsBusy(const char *xlog)
14051408return true;
14061409}
14071410
1411+ /*
1412+ * XLogArchiveIsReady
1413+ *
1414+ * Check to see if an XLOG segment file has an archive notification (.ready)
1415+ * file.
1416+ */
1417+ bool
1418+ XLogArchiveIsReady (const char * xlog )
1419+ {
1420+ char archiveStatusPath [MAXPGPATH ];
1421+ struct stat stat_buf ;
1422+
1423+ StatusFilePath (archiveStatusPath ,xlog ,".ready" );
1424+ if (stat (archiveStatusPath ,& stat_buf )== 0 )
1425+ return true;
1426+
1427+ return false;
1428+ }
1429+
14081430/*
14091431 * XLogArchiveCleanup
14101432 *
@@ -3274,25 +3296,9 @@ UpdateLastRemovedPtr(char *filename)
32743296static void
32753297RemoveOldXlogFiles (uint32 log ,uint32 seg ,XLogRecPtr endptr )
32763298{
3277- uint32 endlogId ;
3278- uint32 endlogSeg ;
3279- int max_advance ;
32803299DIR * xldir ;
32813300struct dirent * xlde ;
32823301char lastoff [MAXFNAMELEN ];
3283- char path [MAXPGPATH ];
3284-
3285- #ifdef WIN32
3286- char newpath [MAXPGPATH ];
3287- #endif
3288- struct stat statbuf ;
3289-
3290- /*
3291- * Initialize info about where to try to recycle to. We allow recycling
3292- * segments up to XLOGfileslop segments beyond the current XLOG location.
3293- */
3294- XLByteToPrevSeg (endptr ,endlogId ,endlogSeg );
3295- max_advance = XLOGfileslop ;
32963302
32973303xldir = AllocateDir (XLOGDIR );
32983304if (xldir == NULL )
@@ -3308,6 +3314,11 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33083314
33093315while ((xlde = ReadDir (xldir ,XLOGDIR ))!= NULL )
33103316{
3317+ /* Ignore files that are not XLOG segments */
3318+ if (strlen (xlde -> d_name )!= 24 ||
3319+ strspn (xlde -> d_name ,"0123456789ABCDEF" )!= 24 )
3320+ continue ;
3321+
33113322/*
33123323 * We ignore the timeline part of the XLOG segment identifiers in
33133324 * deciding whether a segment is still needed. This ensures that we
@@ -3319,9 +3330,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33193330 * We use the alphanumeric sorting property of the filenames to decide
33203331 * which ones are earlier than the lastoff segment.
33213332 */
3322- if (strlen (xlde -> d_name )== 24 &&
3323- strspn (xlde -> d_name ,"0123456789ABCDEF" )== 24 &&
3324- strcmp (xlde -> d_name + 8 ,lastoff + 8 ) <=0 )
3333+ if (strcmp (xlde -> d_name + 8 ,lastoff + 8 ) <=0 )
33253334{
33263335/*
33273336 * Normally we don't delete old XLOG files during recovery to
@@ -3336,86 +3345,107 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33363345 */
33373346if (WalRcvInProgress ()|| XLogArchiveCheckDone (xlde -> d_name ))
33383347{
3339- snprintf (path ,MAXPGPATH ,XLOGDIR "/%s" ,xlde -> d_name );
3340-
33413348/* Update the last removed location in shared memory first */
33423349UpdateLastRemovedPtr (xlde -> d_name );
33433350
3344- /*
3345- * Before deleting the file, see if it can be recycled as a
3346- * future log segment. Only recycle normal files, pg_standby
3347- * for example can create symbolic links pointing to a
3348- * separate archive directory.
3349- */
3350- if (lstat (path ,& statbuf )== 0 && S_ISREG (statbuf .st_mode )&&
3351- InstallXLogFileSegment (& endlogId ,& endlogSeg ,path ,
3352- true,& max_advance , true))
3353- {
3354- ereport (DEBUG2 ,
3355- (errmsg ("recycled transaction log file \"%s\"" ,
3356- xlde -> d_name )));
3357- CheckpointStats .ckpt_segs_recycled ++ ;
3358- /* Needn't recheck that slot on future iterations */
3359- if (max_advance > 0 )
3360- {
3361- NextLogSeg (endlogId ,endlogSeg );
3362- max_advance -- ;
3363- }
3364- }
3365- else
3366- {
3367- /* No need for any more future segments... */
3368- int rc ;
3351+ RemoveXlogFile (xlde -> d_name ,endptr );
3352+ }
3353+ }
3354+ }
33693355
3370- ereport (DEBUG2 ,
3371- (errmsg ("removing transaction log file \"%s\"" ,
3372- xlde -> d_name )));
3356+ FreeDir (xldir );
3357+ }
33733358
3359+ /*
3360+ * Recycle or remove a log file that's no longer needed.
3361+ *
3362+ * endptr is current (or recent) end of xlog; this is used to determine
3363+ * whether we want to recycle rather than delete no-longer-wanted log files.
3364+ */
3365+ static void
3366+ RemoveXlogFile (const char * segname ,XLogRecPtr endptr )
3367+ {
3368+ char path [MAXPGPATH ];
33743369#ifdef WIN32
3370+ char newpath [MAXPGPATH ];
3371+ #endif
3372+ struct stat statbuf ;
3373+ uint32 endlogId ;
3374+ uint32 endlogSeg ;
3375+ int max_advance ;
33753376
3376- /*
3377- * On Windows, if another process (e.g another backend)
3378- * holds the file open in FILE_SHARE_DELETE mode, unlink
3379- * will succeed, but the file will still show up in
3380- * directory listing until the last handle is closed. To
3381- * avoid confusing the lingering deleted file for a live
3382- * WAL file that needs to be archived, rename it before
3383- * deleting it.
3384- *
3385- * If another process holds the file open without
3386- * FILE_SHARE_DELETE flag, rename will fail. We'll try
3387- * again at the next checkpoint.
3388- */
3389- snprintf (newpath ,MAXPGPATH ,"%s.deleted" ,path );
3390- if (rename (path ,newpath )!= 0 )
3391- {
3392- ereport (LOG ,
3393- (errcode_for_file_access (),
3394- errmsg ("could not rename old transaction log file \"%s\": %m" ,
3395- path )));
3396- continue ;
3397- }
3398- rc = unlink (newpath );
3377+ /*
3378+ * Initialize info about where to try to recycle to. We allow recycling
3379+ * segments up to XLOGfileslop segments beyond the current XLOG location.
3380+ */
3381+ XLByteToPrevSeg (endptr ,endlogId ,endlogSeg );
3382+ max_advance = XLOGfileslop ;
3383+
3384+ snprintf (path ,MAXPGPATH ,XLOGDIR "/%s" ,segname );
3385+
3386+ /*
3387+ * Before deleting the file, see if it can be recycled as a future log
3388+ * segment. Only recycle normal files, pg_standby for example can create
3389+ * symbolic links pointing to a separate archive directory.
3390+ */
3391+ if (lstat (path ,& statbuf )== 0 && S_ISREG (statbuf .st_mode )&&
3392+ InstallXLogFileSegment (& endlogId ,& endlogSeg ,path ,
3393+ true,& max_advance , true))
3394+ {
3395+ ereport (DEBUG2 ,
3396+ (errmsg ("recycled transaction log file \"%s\"" ,segname )));
3397+ CheckpointStats .ckpt_segs_recycled ++ ;
3398+ /* Needn't recheck that slot on future iterations */
3399+ if (max_advance > 0 )
3400+ {
3401+ NextLogSeg (endlogId ,endlogSeg );
3402+ max_advance -- ;
3403+ }
3404+ }
3405+ else
3406+ {
3407+ /* No need for any more future segments... */
3408+ int rc ;
3409+
3410+ ereport (DEBUG2 ,
3411+ (errmsg ("removing transaction log file \"%s\"" ,segname )));
3412+
3413+ #ifdef WIN32
3414+ /*
3415+ * On Windows, if another process (e.g another backend) holds the file
3416+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3417+ * will still show up in directory listing until the last handle is
3418+ * closed. To avoid confusing the lingering deleted file for a live
3419+ * WAL file that needs to be archived, rename it before deleting it.
3420+ *
3421+ * If another process holds the file open without FILE_SHARE_DELETE
3422+ * flag, rename will fail. We'll try again at the next checkpoint.
3423+ */
3424+ snprintf (newpath ,MAXPGPATH ,"%s.deleted" ,path );
3425+ if (rename (path ,newpath )!= 0 )
3426+ {
3427+ ereport (LOG ,
3428+ (errcode_for_file_access (),
3429+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3430+ path )));
3431+ return ;
3432+ }
3433+ rc = unlink (newpath );
33993434#else
3400- rc = unlink (path );
3435+ rc = unlink (path );
34013436#endif
3402- if (rc != 0 )
3403- {
3404- ereport (LOG ,
3405- (errcode_for_file_access (),
3406- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3407- path )));
3408- continue ;
3409- }
3410- CheckpointStats .ckpt_segs_removed ++ ;
3411- }
3412-
3413- XLogArchiveCleanup (xlde -> d_name );
3414- }
3437+ if (rc != 0 )
3438+ {
3439+ ereport (LOG ,
3440+ (errcode_for_file_access (),
3441+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3442+ path )));
3443+ return ;
34153444}
3445+ CheckpointStats .ckpt_segs_removed ++ ;
34163446}
34173447
3418- FreeDir ( xldir );
3448+ XLogArchiveCleanup ( segname );
34193449}
34203450
34213451/*
@@ -5501,6 +5531,76 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
55015531(errmsg ("archive recovery complete" )));
55025532}
55035533
5534+ /*
5535+ * Remove WAL files that are not part of the given timeline's history.
5536+ *
5537+ * This is called during recovery, whenever we switch to follow a new
5538+ * timeline, and at the end of recovery when we create a new timeline. We
5539+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
5540+ * can be pre-allocated or recycled WAL segments on the old timeline that we
5541+ * haven't used yet, and contain garbage. If we just leave them in pg_xlog,
5542+ * they will eventually be archived, and we can't let that happen. Files that
5543+ * belong to our timeline history are valid, because we have successfully
5544+ * replayed them, but from others we can't be sure.
5545+ *
5546+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
5547+ * and 'newTLI' is the new timeline we switch to.
5548+ */
5549+ static void
5550+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint ,TimeLineID newTLI )
5551+ {
5552+ DIR * xldir ;
5553+ struct dirent * xlde ;
5554+ char switchseg [MAXFNAMELEN ];
5555+ uint32 endlogId ;
5556+ uint32 endlogSeg ;
5557+
5558+ XLByteToPrevSeg (switchpoint ,endlogId ,endlogSeg );
5559+
5560+ xldir = AllocateDir (XLOGDIR );
5561+ if (xldir == NULL )
5562+ ereport (ERROR ,
5563+ (errcode_for_file_access (),
5564+ errmsg ("could not open transaction log directory \"%s\": %m" ,
5565+ XLOGDIR )));
5566+
5567+ /*
5568+ * Construct a filename of the last segment to be kept.
5569+ */
5570+ XLogFileName (switchseg ,newTLI ,endlogId ,endlogSeg );
5571+
5572+ elog (DEBUG2 ,"attempting to remove WAL segments newer than log file %s" ,
5573+ switchseg );
5574+
5575+ while ((xlde = ReadDir (xldir ,XLOGDIR ))!= NULL )
5576+ {
5577+ /* Ignore files that are not XLOG segments */
5578+ if (strlen (xlde -> d_name )!= 24 ||
5579+ strspn (xlde -> d_name ,"0123456789ABCDEF" )!= 24 )
5580+ continue ;
5581+
5582+ /*
5583+ * Remove files that are on a timeline older than the new one we're
5584+ * switching to, but with a segment number >= the first segment on
5585+ * the new timeline.
5586+ */
5587+ if (strncmp (xlde -> d_name ,switchseg ,8 )< 0 &&
5588+ strcmp (xlde -> d_name + 8 ,switchseg + 8 )> 0 )
5589+ {
5590+ /*
5591+ * If the file has already been marked as .ready, however, don't
5592+ * remove it yet. It should be OK to remove it - files that are
5593+ * not part of our timeline history are not required for recovery
5594+ * - but seems safer to let them be archived and removed later.
5595+ */
5596+ if (!XLogArchiveIsReady (xlde -> d_name ))
5597+ RemoveXlogFile (xlde -> d_name ,switchpoint );
5598+ }
5599+ }
5600+
5601+ FreeDir (xldir );
5602+ }
5603+
55045604/*
55055605 * For point-in-time recovery, this function decides whether we want to
55065606 * stop applying the XLOG at or after the current record.
@@ -5771,6 +5871,7 @@ StartupXLOG(void)
57715871bool wasShutdown ;
57725872bool reachedStopPoint = false;
57735873bool haveBackupLabel = false;
5874+ bool didArchiveRecovery = false;
57745875XLogRecPtr RecPtr ,
57755876checkPointLoc ,
57765877EndOfLog ;
@@ -6469,7 +6570,10 @@ StartupXLOG(void)
64696570 * we will use that below.)
64706571 */
64716572if (InArchiveRecovery )
6573+ {
6574+ didArchiveRecovery = true;
64726575exitArchiveRecovery (curFileTLI ,endLogId ,endLogSeg );
6576+ }
64736577
64746578/*
64756579 * Prepare to write WAL starting at EndOfLog position, and init xlog
@@ -6582,6 +6686,12 @@ StartupXLOG(void)
65826686 true);
65836687}
65846688
6689+ /*
6690+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
6691+ */
6692+ if (didArchiveRecovery )
6693+ RemoveNonParentXlogFiles (EndOfLog ,ThisTimeLineID );
6694+
65856695/*
65866696 * Preallocate additional log files, if wanted.
65876697 */