@@ -791,6 +791,7 @@ static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
791791static void XLogFileClose (void );
792792static void PreallocXlogFiles (XLogRecPtr endptr );
793793static void RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr PriorRedoPtr , XLogRecPtr endptr );
794+ static void RemoveXlogFile (const char * segname , XLogRecPtr PriorRedoPtr , XLogRecPtr endptr );
794795static void UpdateLastRemovedPtr (char * filename );
795796static void ValidateXLOGDirectoryStructure (void );
796797static void CleanupBackupHistory (void );
@@ -3531,7 +3532,7 @@ UpdateLastRemovedPtr(char *filename)
35313532}
35323533
35333534/*
3534- * Recycle or remove all log files older or equal to passed segno
3535+ * Recycle or remove all log files older or equal to passed segno.
35353536 *
35363537 * endptr is current (or recent) end of xlog, and PriorRedoRecPtr is the
35373538 * redo pointer of the previous checkpoint. These are used to determine
@@ -3540,23 +3541,9 @@ UpdateLastRemovedPtr(char *filename)
35403541static void
35413542RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr PriorRedoPtr , XLogRecPtr endptr )
35423543{
3543- XLogSegNo endlogSegNo ;
3544- XLogSegNo recycleSegNo ;
35453544 DIR * xldir ;
35463545 struct dirent * xlde ;
35473546 char lastoff [MAXFNAMELEN ];
3548- char path [MAXPGPATH ];
3549-
3550- #ifdef WIN32
3551- char newpath [MAXPGPATH ];
3552- #endif
3553- struct stat statbuf ;
3554-
3555- /*
3556- * Initialize info about where to try to recycle to.
3557- */
3558- XLByteToPrevSeg (endptr , endlogSegNo );
3559- recycleSegNo = XLOGfileslop (PriorRedoPtr );
35603547
35613548 xldir = AllocateDir (XLOGDIR );
35623549 if (xldir == NULL )
@@ -3577,6 +3564,11 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
35773564
35783565 while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
35793566 {
3567+ /* Ignore files that are not XLOG segments */
3568+ if (strlen (xlde -> d_name ) != 24 ||
3569+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
3570+ continue ;
3571+
35803572 /*
35813573 * We ignore the timeline part of the XLOG segment identifiers in
35823574 * deciding whether a segment is still needed. This ensures that we
@@ -3588,89 +3580,183 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
35883580 * We use the alphanumeric sorting property of the filenames to decide
35893581 * which ones are earlier than the lastoff segment.
35903582 */
3591- if (strlen (xlde -> d_name ) == 24 &&
3592- strspn (xlde -> d_name , "0123456789ABCDEF" ) == 24 &&
3593- strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
3583+ if (strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
35943584 {
35953585 if (XLogArchiveCheckDone (xlde -> d_name ))
35963586 {
3597- snprintf (path , MAXPGPATH , XLOGDIR "/%s" , xlde -> d_name );
3598-
35993587 /* Update the last removed location in shared memory first */
36003588 UpdateLastRemovedPtr (xlde -> d_name );
36013589
3602- /*
3603- * Before deleting the file, see if it can be recycled as a
3604- * future log segment. Only recycle normal files, pg_standby
3605- * for example can create symbolic links pointing to a
3606- * separate archive directory.
3607- */
3608- if (endlogSegNo <= recycleSegNo &&
3609- lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3610- InstallXLogFileSegment (& endlogSegNo , path ,
3611- true, recycleSegNo , true))
3612- {
3613- ereport (DEBUG2 ,
3614- (errmsg ("recycled transaction log file \"%s\"" ,
3615- xlde -> d_name )));
3616- CheckpointStats .ckpt_segs_recycled ++ ;
3617- /* Needn't recheck that slot on future iterations */
3618- endlogSegNo ++ ;
3619- }
3620- else
3621- {
3622- /* No need for any more future segments... */
3623- int rc ;
3590+ RemoveXlogFile (xlde -> d_name , PriorRedoPtr , endptr );
3591+ }
3592+ }
3593+ }
3594+
3595+ FreeDir (xldir );
3596+ }
3597+
3598+ /*
3599+ * Remove WAL files that are not part of the given timeline's history.
3600+ *
3601+ * This is called during recovery, whenever we switch to follow a new
3602+ * timeline, and at the end of recovery when we create a new timeline. We
3603+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
3604+ * might be leftover pre-allocated or recycled WAL segments on the old timeline
3605+ * that we haven't used yet, and contain garbage. If we just leave them in
3606+ * pg_xlog, they will eventually be archived, and we can't let that happen.
3607+ * Files that belong to our timeline history are valid, because we have
3608+ * successfully replayed them, but from others we can't be sure.
3609+ *
3610+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
3611+ * and 'newTLI' is the new timeline we switch to.
3612+ */
3613+ static void
3614+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI )
3615+ {
3616+ DIR * xldir ;
3617+ struct dirent * xlde ;
3618+ char switchseg [MAXFNAMELEN ];
3619+ XLogSegNo endLogSegNo ;
3620+
3621+ XLByteToPrevSeg (switchpoint , endLogSegNo );
3622+
3623+ xldir = AllocateDir (XLOGDIR );
3624+ if (xldir == NULL )
3625+ ereport (ERROR ,
3626+ (errcode_for_file_access (),
3627+ errmsg ("could not open transaction log directory \"%s\": %m" ,
3628+ XLOGDIR )));
36243629
3625- ereport (DEBUG2 ,
3626- (errmsg ("removing transaction log file \"%s\"" ,
3627- xlde -> d_name )));
3630+ /*
3631+ * Construct a filename of the last segment to be kept.
3632+ */
3633+ XLogFileName (switchseg , newTLI , endLogSegNo );
3634+
3635+ elog (DEBUG2 , "attempting to remove WAL segments newer than log file %s" ,
3636+ switchseg );
36283637
3638+ while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
3639+ {
3640+ /* Ignore files that are not XLOG segments */
3641+ if (strlen (xlde -> d_name ) != 24 ||
3642+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
3643+ continue ;
3644+
3645+ /*
3646+ * Remove files that are on a timeline older than the new one we're
3647+ * switching to, but with a segment number >= the first segment on
3648+ * the new timeline.
3649+ */
3650+ if (strncmp (xlde -> d_name , switchseg , 8 ) < 0 &&
3651+ strcmp (xlde -> d_name + 8 , switchseg + 8 ) > 0 )
3652+ {
3653+ /*
3654+ * If the file has already been marked as .ready, however, don't
3655+ * remove it yet. It should be OK to remove it - files that are
3656+ * not part of our timeline history are not required for recovery
3657+ * - but seems safer to let them be archived and removed later.
3658+ */
3659+ if (!XLogArchiveIsReady (xlde -> d_name ))
3660+ RemoveXlogFile (xlde -> d_name , InvalidXLogRecPtr , switchpoint );
3661+ }
3662+ }
3663+
3664+ FreeDir (xldir );
3665+ }
3666+
3667+ /*
3668+ * Recycle or remove a log file that's no longer needed.
3669+ *
3670+ * endptr is current (or recent) end of xlog, and PriorRedoRecPtr is the
3671+ * redo pointer of the previous checkpoint. These are used to determine
3672+ * whether we want to recycle rather than delete no-longer-wanted log files.
3673+ * If PriorRedoRecPtr is not known, pass invalid, and the function will
3674+ * recycle, somewhat arbitrarily, 10 future segments.
3675+ */
3676+ static void
3677+ RemoveXlogFile (const char * segname , XLogRecPtr PriorRedoPtr , XLogRecPtr endptr )
3678+ {
3679+ char path [MAXPGPATH ];
36293680#ifdef WIN32
3681+ char newpath [MAXPGPATH ];
3682+ #endif
3683+ struct stat statbuf ;
3684+ XLogSegNo endlogSegNo ;
3685+ XLogSegNo recycleSegNo ;
36303686
3631- /*
3632- * On Windows, if another process (e.g another backend)
3633- * holds the file open in FILE_SHARE_DELETE mode, unlink
3634- * will succeed, but the file will still show up in
3635- * directory listing until the last handle is closed. To
3636- * avoid confusing the lingering deleted file for a live
3637- * WAL file that needs to be archived, rename it before
3638- * deleting it.
3639- *
3640- * If another process holds the file open without
3641- * FILE_SHARE_DELETE flag, rename will fail. We'll try
3642- * again at the next checkpoint.
3643- */
3644- snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3645- if (rename (path , newpath ) != 0 )
3646- {
3647- ereport (LOG ,
3648- (errcode_for_file_access (),
3649- errmsg ("could not rename old transaction log file \"%s\": %m" ,
3650- path )));
3651- continue ;
3652- }
3653- rc = unlink (newpath );
3687+ /*
3688+ * Initialize info about where to try to recycle to.
3689+ */
3690+ XLByteToPrevSeg (endptr , endlogSegNo );
3691+ if (PriorRedoPtr == InvalidXLogRecPtr )
3692+ recycleSegNo = endlogSegNo + 10 ;
3693+ else
3694+ recycleSegNo = XLOGfileslop (PriorRedoPtr );
3695+
3696+ snprintf (path , MAXPGPATH , XLOGDIR "/%s" , segname );
3697+
3698+ /*
3699+ * Before deleting the file, see if it can be recycled as a future log
3700+ * segment. Only recycle normal files, pg_standby for example can create
3701+ * symbolic links pointing to a separate archive directory.
3702+ */
3703+ if (endlogSegNo <= recycleSegNo &&
3704+ lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3705+ InstallXLogFileSegment (& endlogSegNo , path ,
3706+ true, recycleSegNo , true))
3707+ {
3708+ ereport (DEBUG2 ,
3709+ (errmsg ("recycled transaction log file \"%s\"" ,
3710+ segname )));
3711+ CheckpointStats .ckpt_segs_recycled ++ ;
3712+ /* Needn't recheck that slot on future iterations */
3713+ endlogSegNo ++ ;
3714+ }
3715+ else
3716+ {
3717+ /* No need for any more future segments... */
3718+ int rc ;
3719+
3720+ ereport (DEBUG2 ,
3721+ (errmsg ("removing transaction log file \"%s\"" ,
3722+ segname )));
3723+
3724+ #ifdef WIN32
3725+ /*
3726+ * On Windows, if another process (e.g another backend) holds the file
3727+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3728+ * will still show up in directory listing until the last handle is
3729+ * closed. To avoid confusing the lingering deleted file for a live WAL
3730+ * file that needs to be archived, rename it before deleting it.
3731+ *
3732+ * If another process holds the file open without FILE_SHARE_DELETE
3733+ * flag, rename will fail. We'll try again at the next checkpoint.
3734+ */
3735+ snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3736+ if (rename (path , newpath ) != 0 )
3737+ {
3738+ ereport (LOG ,
3739+ (errcode_for_file_access (),
3740+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3741+ path )));
3742+ return ;
3743+ }
3744+ rc = unlink (newpath );
36543745#else
3655- rc = unlink (path );
3746+ rc = unlink (path );
36563747#endif
3657- if (rc != 0 )
3658- {
3659- ereport (LOG ,
3660- (errcode_for_file_access (),
3661- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3662- path )));
3663- continue ;
3664- }
3665- CheckpointStats .ckpt_segs_removed ++ ;
3666- }
3667-
3668- XLogArchiveCleanup (xlde -> d_name );
3669- }
3748+ if (rc != 0 )
3749+ {
3750+ ereport (LOG ,
3751+ (errcode_for_file_access (),
3752+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3753+ path )));
3754+ return ;
36703755 }
3756+ CheckpointStats .ckpt_segs_removed ++ ;
36713757 }
36723758
3673- FreeDir ( xldir );
3759+ XLogArchiveCleanup ( segname );
36743760}
36753761
36763762/*
@@ -6626,12 +6712,22 @@ StartupXLOG(void)
66266712 /* Allow read-only connections if we're consistent now */
66276713 CheckRecoveryConsistency ();
66286714
6629- /*
6630- * If this record was a timeline switch, wake up any
6631- * walsenders to notice that we are on a new timeline.
6632- */
6633- if (switchedTLI && AllowCascadeReplication ())
6634- WalSndWakeup ();
6715+ /* Is this a timeline switch? */
6716+ if (switchedTLI )
6717+ {
6718+ /*
6719+ * Before we continue on the new timeline, clean up any
6720+ * (possibly bogus) future WAL segments on the old timeline.
6721+ */
6722+ RemoveNonParentXlogFiles (EndRecPtr , ThisTimeLineID );
6723+
6724+ /*
6725+ * Wake up any walsenders to notice that we are on a new
6726+ * timeline.
6727+ */
6728+ if (switchedTLI && AllowCascadeReplication ())
6729+ WalSndWakeup ();
6730+ }
66356731
66366732 /* Exit loop if we reached inclusive recovery target */
66376733 if (recoveryStopsAfter (xlogreader ))
@@ -6975,6 +7071,12 @@ StartupXLOG(void)
69757071 true);
69767072 }
69777073
7074+ /*
7075+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
7076+ */
7077+ if (ArchiveRecoveryRequested )
7078+ RemoveNonParentXlogFiles (EndOfLog , ThisTimeLineID );
7079+
69787080 /*
69797081 * Preallocate additional log files, if wanted.
69807082 */
0 commit comments