@@ -609,6 +609,7 @@ static void XLogArchiveNotify(const char *xlog);
609609static void XLogArchiveNotifySeg (uint32 log , uint32 seg );
610610static bool XLogArchiveCheckDone (const char * xlog );
611611static bool XLogArchiveIsBusy (const char * xlog );
612+ extern bool XLogArchiveIsReady (const char * xlog );
612613static void XLogArchiveCleanup (const char * xlog );
613614static void readRecoveryCommandFile (void );
614615static void exitArchiveRecovery (TimeLineID endTLI ,
@@ -646,6 +647,8 @@ static void ExecuteRecoveryCommand(char *command, char *commandName,
646647 bool failOnerror );
647648static void PreallocXlogFiles (XLogRecPtr endptr );
648649static void RemoveOldXlogFiles (uint32 log , uint32 seg , XLogRecPtr endptr );
650+ static void RemoveXlogFile (const char * segname , XLogRecPtr endptr );
651+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI );
649652static void UpdateLastRemovedPtr (char * filename );
650653static void ValidateXLOGDirectoryStructure (void );
651654static void CleanupBackupHistory (void );
@@ -1455,6 +1458,25 @@ XLogArchiveIsBusy(const char *xlog)
14551458 return true;
14561459}
14571460
1461+ /*
1462+ * XLogArchiveIsReady
1463+ *
1464+ * Check to see if an XLOG segment file has an archive notification (.ready)
1465+ * file.
1466+ */
1467+ bool
1468+ XLogArchiveIsReady (const char * xlog )
1469+ {
1470+ char archiveStatusPath [MAXPGPATH ];
1471+ struct stat stat_buf ;
1472+
1473+ StatusFilePath (archiveStatusPath , xlog , ".ready" );
1474+ if (stat (archiveStatusPath , & stat_buf ) == 0 )
1475+ return true;
1476+
1477+ return false;
1478+ }
1479+
14581480/*
14591481 * XLogArchiveCleanup
14601482 *
@@ -3332,25 +3354,9 @@ UpdateLastRemovedPtr(char *filename)
33323354static void
33333355RemoveOldXlogFiles (uint32 log , uint32 seg , XLogRecPtr endptr )
33343356{
3335- uint32 endlogId ;
3336- uint32 endlogSeg ;
3337- int max_advance ;
33383357 DIR * xldir ;
33393358 struct dirent * xlde ;
33403359 char lastoff [MAXFNAMELEN ];
3341- char path [MAXPGPATH ];
3342-
3343- #ifdef WIN32
3344- char newpath [MAXPGPATH ];
3345- #endif
3346- struct stat statbuf ;
3347-
3348- /*
3349- * Initialize info about where to try to recycle to. We allow recycling
3350- * segments up to XLOGfileslop segments beyond the current XLOG location.
3351- */
3352- XLByteToPrevSeg (endptr , endlogId , endlogSeg );
3353- max_advance = XLOGfileslop ;
33543360
33553361 xldir = AllocateDir (XLOGDIR );
33563362 if (xldir == NULL )
@@ -3366,6 +3372,11 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33663372
33673373 while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
33683374 {
3375+ /* Ignore files that are not XLOG segments */
3376+ if (strlen (xlde -> d_name ) != 24 ||
3377+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
3378+ continue ;
3379+
33693380 /*
33703381 * We ignore the timeline part of the XLOG segment identifiers in
33713382 * deciding whether a segment is still needed. This ensures that we
@@ -3377,9 +3388,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33773388 * We use the alphanumeric sorting property of the filenames to decide
33783389 * which ones are earlier than the lastoff segment.
33793390 */
3380- if (strlen (xlde -> d_name ) == 24 &&
3381- strspn (xlde -> d_name , "0123456789ABCDEF" ) == 24 &&
3382- strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
3391+ if (strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
33833392 {
33843393 /*
33853394 * Normally we don't delete old XLOG files during recovery to
@@ -3394,86 +3403,107 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
33943403 */
33953404 if (WalRcvInProgress () || XLogArchiveCheckDone (xlde -> d_name ))
33963405 {
3397- snprintf (path , MAXPGPATH , XLOGDIR "/%s" , xlde -> d_name );
3398-
33993406 /* Update the last removed location in shared memory first */
34003407 UpdateLastRemovedPtr (xlde -> d_name );
34013408
3402- /*
3403- * Before deleting the file, see if it can be recycled as a
3404- * future log segment. Only recycle normal files, pg_standby
3405- * for example can create symbolic links pointing to a
3406- * separate archive directory.
3407- */
3408- if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3409- InstallXLogFileSegment (& endlogId , & endlogSeg , path ,
3410- true, & max_advance , true))
3411- {
3412- ereport (DEBUG2 ,
3413- (errmsg ("recycled transaction log file \"%s\"" ,
3414- xlde -> d_name )));
3415- CheckpointStats .ckpt_segs_recycled ++ ;
3416- /* Needn't recheck that slot on future iterations */
3417- if (max_advance > 0 )
3418- {
3419- NextLogSeg (endlogId , endlogSeg );
3420- max_advance -- ;
3421- }
3422- }
3423- else
3424- {
3425- /* No need for any more future segments... */
3426- int rc ;
3409+ RemoveXlogFile (xlde -> d_name , endptr );
3410+ }
3411+ }
3412+ }
34273413
3428- ereport (DEBUG2 ,
3429- (errmsg ("removing transaction log file \"%s\"" ,
3430- xlde -> d_name )));
3414+ FreeDir (xldir );
3415+ }
34313416
3417+ /*
3418+ * Recycle or remove a log file that's no longer needed.
3419+ *
3420+ * endptr is current (or recent) end of xlog; this is used to determine
3421+ * whether we want to recycle rather than delete no-longer-wanted log files.
3422+ */
3423+ static void
3424+ RemoveXlogFile (const char * segname , XLogRecPtr endptr )
3425+ {
3426+ char path [MAXPGPATH ];
34323427#ifdef WIN32
3428+ char newpath [MAXPGPATH ];
3429+ #endif
3430+ struct stat statbuf ;
3431+ uint32 endlogId ;
3432+ uint32 endlogSeg ;
3433+ int max_advance ;
34333434
3434- /*
3435- * On Windows, if another process (e.g another backend)
3436- * holds the file open in FILE_SHARE_DELETE mode, unlink
3437- * will succeed, but the file will still show up in
3438- * directory listing until the last handle is closed. To
3439- * avoid confusing the lingering deleted file for a live
3440- * WAL file that needs to be archived, rename it before
3441- * deleting it.
3442- *
3443- * If another process holds the file open without
3444- * FILE_SHARE_DELETE flag, rename will fail. We'll try
3445- * again at the next checkpoint.
3446- */
3447- snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3448- if (rename (path , newpath ) != 0 )
3449- {
3450- ereport (LOG ,
3451- (errcode_for_file_access (),
3452- errmsg ("could not rename old transaction log file \"%s\": %m" ,
3453- path )));
3454- continue ;
3455- }
3456- rc = unlink (newpath );
3435+ /*
3436+ * Initialize info about where to try to recycle to. We allow recycling
3437+ * segments up to XLOGfileslop segments beyond the current XLOG location.
3438+ */
3439+ XLByteToPrevSeg (endptr , endlogId , endlogSeg );
3440+ max_advance = XLOGfileslop ;
3441+
3442+ snprintf (path , MAXPGPATH , XLOGDIR "/%s" , segname );
3443+
3444+ /*
3445+ * Before deleting the file, see if it can be recycled as a future log
3446+ * segment. Only recycle normal files, pg_standby for example can create
3447+ * symbolic links pointing to a separate archive directory.
3448+ */
3449+ if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3450+ InstallXLogFileSegment (& endlogId , & endlogSeg , path ,
3451+ true, & max_advance , true))
3452+ {
3453+ ereport (DEBUG2 ,
3454+ (errmsg ("recycled transaction log file \"%s\"" , segname )));
3455+ CheckpointStats .ckpt_segs_recycled ++ ;
3456+ /* Needn't recheck that slot on future iterations */
3457+ if (max_advance > 0 )
3458+ {
3459+ NextLogSeg (endlogId , endlogSeg );
3460+ max_advance -- ;
3461+ }
3462+ }
3463+ else
3464+ {
3465+ /* No need for any more future segments... */
3466+ int rc ;
3467+
3468+ ereport (DEBUG2 ,
3469+ (errmsg ("removing transaction log file \"%s\"" , segname )));
3470+
3471+ #ifdef WIN32
3472+ /*
3473+ * On Windows, if another process (e.g another backend) holds the file
3474+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3475+ * will still show up in directory listing until the last handle is
3476+ * closed. To avoid confusing the lingering deleted file for a live
3477+ * WAL file that needs to be archived, rename it before deleting it.
3478+ *
3479+ * If another process holds the file open without FILE_SHARE_DELETE
3480+ * flag, rename will fail. We'll try again at the next checkpoint.
3481+ */
3482+ snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3483+ if (rename (path , newpath ) != 0 )
3484+ {
3485+ ereport (LOG ,
3486+ (errcode_for_file_access (),
3487+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3488+ path )));
3489+ return ;
3490+ }
3491+ rc = unlink (newpath );
34573492#else
3458- rc = unlink (path );
3493+ rc = unlink (path );
34593494#endif
3460- if (rc != 0 )
3461- {
3462- ereport (LOG ,
3463- (errcode_for_file_access (),
3464- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3465- path )));
3466- continue ;
3467- }
3468- CheckpointStats .ckpt_segs_removed ++ ;
3469- }
3470-
3471- XLogArchiveCleanup (xlde -> d_name );
3472- }
3495+ if (rc != 0 )
3496+ {
3497+ ereport (LOG ,
3498+ (errcode_for_file_access (),
3499+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3500+ path )));
3501+ return ;
34733502 }
3503+ CheckpointStats .ckpt_segs_removed ++ ;
34743504 }
34753505
3476- FreeDir ( xldir );
3506+ XLogArchiveCleanup ( segname );
34773507}
34783508
34793509/*
@@ -5629,6 +5659,76 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
56295659 (errmsg ("archive recovery complete" )));
56305660}
56315661
5662+ /*
5663+ * Remove WAL files that are not part of the given timeline's history.
5664+ *
5665+ * This is called during recovery, whenever we switch to follow a new
5666+ * timeline, and at the end of recovery when we create a new timeline. We
5667+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
5668+ * can be pre-allocated or recycled WAL segments on the old timeline that we
5669+ * haven't used yet, and contain garbage. If we just leave them in pg_xlog,
5670+ * they will eventually be archived, and we can't let that happen. Files that
5671+ * belong to our timeline history are valid, because we have successfully
5672+ * replayed them, but from others we can't be sure.
5673+ *
5674+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
5675+ * and 'newTLI' is the new timeline we switch to.
5676+ */
5677+ static void
5678+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI )
5679+ {
5680+ DIR * xldir ;
5681+ struct dirent * xlde ;
5682+ char switchseg [MAXFNAMELEN ];
5683+ uint32 endlogId ;
5684+ uint32 endlogSeg ;
5685+
5686+ XLByteToPrevSeg (switchpoint , endlogId , endlogSeg );
5687+
5688+ xldir = AllocateDir (XLOGDIR );
5689+ if (xldir == NULL )
5690+ ereport (ERROR ,
5691+ (errcode_for_file_access (),
5692+ errmsg ("could not open transaction log directory \"%s\": %m" ,
5693+ XLOGDIR )));
5694+
5695+ /*
5696+ * Construct a filename of the last segment to be kept.
5697+ */
5698+ XLogFileName (switchseg , newTLI , endlogId , endlogSeg );
5699+
5700+ elog (DEBUG2 , "attempting to remove WAL segments newer than log file %s" ,
5701+ switchseg );
5702+
5703+ while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
5704+ {
5705+ /* Ignore files that are not XLOG segments */
5706+ if (strlen (xlde -> d_name ) != 24 ||
5707+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
5708+ continue ;
5709+
5710+ /*
5711+ * Remove files that are on a timeline older than the new one we're
5712+ * switching to, but with a segment number >= the first segment on
5713+ * the new timeline.
5714+ */
5715+ if (strncmp (xlde -> d_name , switchseg , 8 ) < 0 &&
5716+ strcmp (xlde -> d_name + 8 , switchseg + 8 ) > 0 )
5717+ {
5718+ /*
5719+ * If the file has already been marked as .ready, however, don't
5720+ * remove it yet. It should be OK to remove it - files that are
5721+ * not part of our timeline history are not required for recovery
5722+ * - but seems safer to let them be archived and removed later.
5723+ */
5724+ if (!XLogArchiveIsReady (xlde -> d_name ))
5725+ RemoveXlogFile (xlde -> d_name , switchpoint );
5726+ }
5727+ }
5728+
5729+ FreeDir (xldir );
5730+ }
5731+
56325732/*
56335733 * For point-in-time recovery, this function decides whether we want to
56345734 * stop applying the XLOG at or after the current record.
@@ -6075,6 +6175,7 @@ StartupXLOG(void)
60756175 bool wasShutdown ;
60766176 bool reachedStopPoint = false;
60776177 bool haveBackupLabel = false;
6178+ bool didArchiveRecovery = false;
60786179 XLogRecPtr RecPtr ,
60796180 checkPointLoc ,
60806181 EndOfLog ;
@@ -6844,7 +6945,10 @@ StartupXLOG(void)
68446945 * we will use that below.)
68456946 */
68466947 if (InArchiveRecovery )
6948+ {
6949+ didArchiveRecovery = true;
68476950 exitArchiveRecovery (curFileTLI , endLogId , endLogSeg );
6951+ }
68486952
68496953 /*
68506954 * Prepare to write WAL starting at EndOfLog position, and init xlog
@@ -6957,6 +7061,12 @@ StartupXLOG(void)
69577061 true);
69587062 }
69597063
7064+ /*
7065+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
7066+ */
7067+ if (didArchiveRecovery )
7068+ RemoveNonParentXlogFiles (EndOfLog , ThisTimeLineID );
7069+
69607070 /*
69617071 * Preallocate additional log files, if wanted.
69627072 */
0 commit comments