@@ -669,6 +669,8 @@ static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
669669static void XLogFileClose (void );
670670static void PreallocXlogFiles (XLogRecPtr endptr );
671671static void RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr endptr );
672+ static void RemoveXlogFile (const char * segname , XLogRecPtr endptr );
673+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI );
672674static void UpdateLastRemovedPtr (char * filename );
673675static void ValidateXLOGDirectoryStructure (void );
674676static void CleanupBackupHistory (void );
@@ -2876,32 +2878,17 @@ UpdateLastRemovedPtr(char *filename)
28762878}
28772879
28782880/*
2879- * Recycle or remove all log files older or equal to passed segno
2881+ * Recycle or remove all log files older or equal to passed segno.
28802882 *
28812883 * endptr is current (or recent) end of xlog; this is used to determine
28822884 * whether we want to recycle rather than delete no-longer-wanted log files.
28832885 */
28842886static void
28852887RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr endptr )
28862888{
2887- XLogSegNo endlogSegNo ;
2888- int max_advance ;
28892889 DIR * xldir ;
28902890 struct dirent * xlde ;
28912891 char lastoff [MAXFNAMELEN ];
2892- char path [MAXPGPATH ];
2893-
2894- #ifdef WIN32
2895- char newpath [MAXPGPATH ];
2896- #endif
2897- struct stat statbuf ;
2898-
2899- /*
2900- * Initialize info about where to try to recycle to. We allow recycling
2901- * segments up to XLOGfileslop segments beyond the current XLOG location.
2902- */
2903- XLByteToPrevSeg (endptr , endlogSegNo );
2904- max_advance = XLOGfileslop ;
29052892
29062893 xldir = AllocateDir (XLOGDIR );
29072894 if (xldir == NULL )
@@ -2922,6 +2909,11 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
29222909
29232910 while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
29242911 {
2912+ /* Ignore files that are not XLOG segments */
2913+ if (strlen (xlde -> d_name ) != 24 ||
2914+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
2915+ continue ;
2916+
29252917 /*
29262918 * We ignore the timeline part of the XLOG segment identifiers in
29272919 * deciding whether a segment is still needed. This ensures that we
@@ -2933,92 +2925,110 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
29332925 * We use the alphanumeric sorting property of the filenames to decide
29342926 * which ones are earlier than the lastoff segment.
29352927 */
2936- if (strlen (xlde -> d_name ) == 24 &&
2937- strspn (xlde -> d_name , "0123456789ABCDEF" ) == 24 &&
2938- strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
2928+ if (strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
29392929 {
29402930 if (XLogArchiveCheckDone (xlde -> d_name ))
29412931 {
2942- snprintf (path , MAXPGPATH , XLOGDIR "/%s" , xlde -> d_name );
2943-
29442932 /* Update the last removed location in shared memory first */
29452933 UpdateLastRemovedPtr (xlde -> d_name );
29462934
2947- /*
2948- * Before deleting the file, see if it can be recycled as a
2949- * future log segment. Only recycle normal files, pg_standby
2950- * for example can create symbolic links pointing to a
2951- * separate archive directory.
2952- */
2953- if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
2954- InstallXLogFileSegment (& endlogSegNo , path ,
2955- true, & max_advance , true))
2956- {
2957- ereport (DEBUG2 ,
2958- (errmsg ("recycled transaction log file \"%s\"" ,
2959- xlde -> d_name )));
2960- CheckpointStats .ckpt_segs_recycled ++ ;
2961- /* Needn't recheck that slot on future iterations */
2962- if (max_advance > 0 )
2963- {
2964- endlogSegNo ++ ;
2965- max_advance -- ;
2966- }
2967- }
2968- else
2969- {
2970- /* No need for any more future segments... */
2971- int rc ;
2935+ RemoveXlogFile (xlde -> d_name , endptr );
2936+ }
2937+ }
2938+ }
29722939
2973- ereport (DEBUG2 ,
2974- (errmsg ("removing transaction log file \"%s\"" ,
2975- xlde -> d_name )));
2940+ FreeDir (xldir );
2941+ }
29762942
2943+ /*
2944+ * Recycle or remove a log file that's no longer needed.
2945+ *
2946+ * endptr is current (or recent) end of xlog; this is used to determine
2947+ * whether we want to recycle rather than delete no-longer-wanted log files.
2948+ */
2949+ static void
2950+ RemoveXlogFile (const char * segname , XLogRecPtr endptr )
2951+ {
2952+ char path [MAXPGPATH ];
29772953#ifdef WIN32
2954+ char newpath [MAXPGPATH ];
2955+ #endif
2956+ struct stat statbuf ;
2957+ XLogSegNo endlogSegNo ;
2958+ int max_advance ;
29782959
2979- /*
2980- * On Windows, if another process (e.g another backend)
2981- * holds the file open in FILE_SHARE_DELETE mode, unlink
2982- * will succeed, but the file will still show up in
2983- * directory listing until the last handle is closed. To
2984- * avoid confusing the lingering deleted file for a live
2985- * WAL file that needs to be archived, rename it before
2986- * deleting it.
2987- *
2988- * If another process holds the file open without
2989- * FILE_SHARE_DELETE flag, rename will fail. We'll try
2990- * again at the next checkpoint.
2991- */
2992- snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
2993- if (rename (path , newpath ) != 0 )
2994- {
2995- ereport (LOG ,
2996- (errcode_for_file_access (),
2997- errmsg ("could not rename old transaction log file \"%s\": %m" ,
2998- path )));
2999- continue ;
3000- }
3001- rc = unlink (newpath );
2960+ /*
2961+ * Initialize info about where to try to recycle to. We allow recycling
2962+ * segments up to XLOGfileslop segments beyond the current XLOG location.
2963+ */
2964+ XLByteToPrevSeg (endptr , endlogSegNo );
2965+ max_advance = XLOGfileslop ;
2966+
2967+ snprintf (path , MAXPGPATH , XLOGDIR "/%s" , segname );
2968+
2969+ /*
2970+ * Before deleting the file, see if it can be recycled as a future log
2971+ * segment. Only recycle normal files, pg_standby for example can create
2972+ * symbolic links pointing to a separate archive directory.
2973+ */
2974+ if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
2975+ InstallXLogFileSegment (& endlogSegNo , path ,
2976+ true, & max_advance , true))
2977+ {
2978+ ereport (DEBUG2 ,
2979+ (errmsg ("recycled transaction log file \"%s\"" , segname )));
2980+ CheckpointStats .ckpt_segs_recycled ++ ;
2981+ /* Needn't recheck that slot on future iterations */
2982+ if (max_advance > 0 )
2983+ {
2984+ endlogSegNo ++ ;
2985+ max_advance -- ;
2986+ }
2987+ }
2988+ else
2989+ {
2990+ /* No need for any more future segments... */
2991+ int rc ;
2992+
2993+ ereport (DEBUG2 ,
2994+ (errmsg ("removing transaction log file \"%s\"" , segname )));
2995+
2996+ #ifdef WIN32
2997+ /*
2998+ * On Windows, if another process (e.g another backend) holds the file
2999+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3000+ * will still show up in directory listing until the last handle is
3001+ * closed. To avoid confusing the lingering deleted file for a live
3002+ * WAL file that needs to be archived, rename it before deleting it.
3003+ *
3004+ * If another process holds the file open without FILE_SHARE_DELETE
3005+ * flag, rename will fail. We'll try again at the next checkpoint.
3006+ */
3007+ snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3008+ if (rename (path , newpath ) != 0 )
3009+ {
3010+ ereport (LOG ,
3011+ (errcode_for_file_access (),
3012+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3013+ path )));
3014+ return ;
3015+ }
3016+ rc = unlink (newpath );
30023017#else
3003- rc = unlink (path );
3018+ rc = unlink (path );
30043019#endif
3005- if (rc != 0 )
3006- {
3007- ereport (LOG ,
3008- (errcode_for_file_access (),
3009- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3010- path )));
3011- continue ;
3012- }
3013- CheckpointStats .ckpt_segs_removed ++ ;
3014- }
3015-
3016- XLogArchiveCleanup (xlde -> d_name );
3017- }
3020+ if (rc != 0 )
3021+ {
3022+ ereport (LOG ,
3023+ (errcode_for_file_access (),
3024+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3025+ path )));
3026+ return ;
30183027 }
3028+ CheckpointStats .ckpt_segs_removed ++ ;
30193029 }
30203030
3021- FreeDir ( xldir );
3031+ XLogArchiveCleanup ( segname );
30223032}
30233033
30243034/*
@@ -4474,6 +4484,75 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
44744484 (errmsg ("archive recovery complete" )));
44754485}
44764486
4487+ /*
4488+ * Remove WAL files that are not part of the given timeline's history.
4489+ *
4490+ * This is called during recovery, whenever we switch to follow a new
4491+ * timeline, and at the end of recovery when we create a new timeline. We
4492+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
4493+ * can be pre-allocated or recycled WAL segments on the old timeline that we
4494+ * haven't used yet, and contain garbage. If we just leave them in pg_xlog,
4495+ * they will eventually be archived, and we can't let that happen. Files that
4496+ * belong to our timeline history are valid, because we have successfully
4497+ * replayed them, but from others we can't be sure.
4498+ *
4499+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
4500+ * and 'newTLI' is the new timeline we switch to.
4501+ */
4502+ static void
4503+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI )
4504+ {
4505+ DIR * xldir ;
4506+ struct dirent * xlde ;
4507+ char switchseg [MAXFNAMELEN ];
4508+ XLogSegNo endLogSegNo ;
4509+
4510+ XLByteToPrevSeg (switchpoint , endLogSegNo );
4511+
4512+ xldir = AllocateDir (XLOGDIR );
4513+ if (xldir == NULL )
4514+ ereport (ERROR ,
4515+ (errcode_for_file_access (),
4516+ errmsg ("could not open transaction log directory \"%s\": %m" ,
4517+ XLOGDIR )));
4518+
4519+ /*
4520+ * Construct a filename of the last segment to be kept.
4521+ */
4522+ XLogFileName (switchseg , newTLI , endLogSegNo );
4523+
4524+ elog (DEBUG2 , "attempting to remove WAL segments newer than log file %s" ,
4525+ switchseg );
4526+
4527+ while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
4528+ {
4529+ /* Ignore files that are not XLOG segments */
4530+ if (strlen (xlde -> d_name ) != 24 ||
4531+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
4532+ continue ;
4533+
4534+ /*
4535+ * Remove files that are on a timeline older than the new one we're
4536+ * switching to, but with a segment number >= the first segment on
4537+ * the new timeline.
4538+ */
4539+ if (strncmp (xlde -> d_name , switchseg , 8 ) < 0 &&
4540+ strcmp (xlde -> d_name + 8 , switchseg + 8 ) > 0 )
4541+ {
4542+ /*
4543+ * If the file has already been marked as .ready, however, don't
4544+ * remove it yet. It should be OK to remove it - files that are
4545+ * not part of our timeline history are not required for recovery
4546+ * - but seems safer to let them be archived and removed later.
4547+ */
4548+ if (!XLogArchiveIsReady (xlde -> d_name ))
4549+ RemoveXlogFile (xlde -> d_name , switchpoint );
4550+ }
4551+ }
4552+
4553+ FreeDir (xldir );
4554+ }
4555+
44774556/*
44784557 * For point-in-time recovery, this function decides whether we want to
44794558 * stop applying the XLOG at or after the current record.
@@ -5647,9 +5726,9 @@ StartupXLOG(void)
56475726 */
56485727 if (record -> xl_rmid == RM_XLOG_ID )
56495728 {
5729+ uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
56505730 TimeLineID newTLI = ThisTimeLineID ;
56515731 TimeLineID prevTLI = ThisTimeLineID ;
5652- uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
56535732
56545733 if (info == XLOG_CHECKPOINT_SHUTDOWN )
56555734 {
@@ -5717,12 +5796,21 @@ StartupXLOG(void)
57175796 /* Allow read-only connections if we're consistent now */
57185797 CheckRecoveryConsistency ();
57195798
5720- /*
5721- * If this record was a timeline switch, wake up any
5722- * walsenders to notice that we are on a new timeline.
5723- */
5724- if (switchedTLI && AllowCascadeReplication ())
5725- WalSndWakeup ();
5799+ if (switchedTLI )
5800+ {
5801+ /*
5802+ * Before we go further on the new timeline, clean up any
5803+ * (possibly bogus) future WAL segments on the old one.
5804+ */
5805+ RemoveNonParentXlogFiles (EndRecPtr , ThisTimeLineID );
5806+
5807+ /*
5808+ * Wake up any walsenders to notice that we are on a new
5809+ * timeline.
5810+ */
5811+ if (AllowCascadeReplication ())
5812+ WalSndWakeup ();
5813+ }
57265814
57275815 /* Exit loop if we reached inclusive recovery target */
57285816 if (!recoveryContinue )
@@ -6059,6 +6147,12 @@ StartupXLOG(void)
60596147 true);
60606148 }
60616149
6150+ /*
6151+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
6152+ */
6153+ if (ArchiveRecoveryRequested )
6154+ RemoveNonParentXlogFiles (EndOfLog , ThisTimeLineID );
6155+
60626156 /*
60636157 * Preallocate additional log files, if wanted.
60646158 */
0 commit comments