@@ -669,6 +669,8 @@ static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
669
669
static void XLogFileClose (void );
670
670
static void PreallocXlogFiles (XLogRecPtr endptr );
671
671
static void RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr endptr );
672
+ static void RemoveXlogFile (const char * segname , XLogRecPtr endptr );
673
+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI );
672
674
static void UpdateLastRemovedPtr (char * filename );
673
675
static void ValidateXLOGDirectoryStructure (void );
674
676
static void CleanupBackupHistory (void );
@@ -2876,32 +2878,17 @@ UpdateLastRemovedPtr(char *filename)
2876
2878
}
2877
2879
2878
2880
/*
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.
2880
2882
*
2881
2883
* endptr is current (or recent) end of xlog; this is used to determine
2882
2884
* whether we want to recycle rather than delete no-longer-wanted log files.
2883
2885
*/
2884
2886
static void
2885
2887
RemoveOldXlogFiles (XLogSegNo segno , XLogRecPtr endptr )
2886
2888
{
2887
- XLogSegNo endlogSegNo ;
2888
- int max_advance ;
2889
2889
DIR * xldir ;
2890
2890
struct dirent * xlde ;
2891
2891
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 ;
2905
2892
2906
2893
xldir = AllocateDir (XLOGDIR );
2907
2894
if (xldir == NULL )
@@ -2922,6 +2909,11 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
2922
2909
2923
2910
while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
2924
2911
{
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
+
2925
2917
/*
2926
2918
* We ignore the timeline part of the XLOG segment identifiers in
2927
2919
* deciding whether a segment is still needed. This ensures that we
@@ -2933,92 +2925,110 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
2933
2925
* We use the alphanumeric sorting property of the filenames to decide
2934
2926
* which ones are earlier than the lastoff segment.
2935
2927
*/
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 )
2939
2929
{
2940
2930
if (XLogArchiveCheckDone (xlde -> d_name ))
2941
2931
{
2942
- snprintf (path , MAXPGPATH , XLOGDIR "/%s" , xlde -> d_name );
2943
-
2944
2932
/* Update the last removed location in shared memory first */
2945
2933
UpdateLastRemovedPtr (xlde -> d_name );
2946
2934
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
+ }
2972
2939
2973
- ereport (DEBUG2 ,
2974
- (errmsg ("removing transaction log file \"%s\"" ,
2975
- xlde -> d_name )));
2940
+ FreeDir (xldir );
2941
+ }
2976
2942
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 ];
2977
2953
#ifdef WIN32
2954
+ char newpath [MAXPGPATH ];
2955
+ #endif
2956
+ struct stat statbuf ;
2957
+ XLogSegNo endlogSegNo ;
2958
+ int max_advance ;
2978
2959
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 );
3002
3017
#else
3003
- rc = unlink (path );
3018
+ rc = unlink (path );
3004
3019
#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 ;
3018
3027
}
3028
+ CheckpointStats .ckpt_segs_removed ++ ;
3019
3029
}
3020
3030
3021
- FreeDir ( xldir );
3031
+ XLogArchiveCleanup ( segname );
3022
3032
}
3023
3033
3024
3034
/*
@@ -4474,6 +4484,75 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
4474
4484
(errmsg ("archive recovery complete" )));
4475
4485
}
4476
4486
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<
10000
/code>
+ 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
+
4477
4556
/*
4478
4557
* For point-in-time recovery, this function decides whether we want to
4479
4558
* stop applying the XLOG at or after the current record.
@@ -5647,9 +5726,9 @@ StartupXLOG(void)
5647
5726
*/
5648
5727
if (record -> xl_rmid == RM_XLOG_ID )
5649
5728
{
5729
+ uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
5650
5730
TimeLineID newTLI = ThisTimeLineID ;
5651
5731
TimeLineID prevTLI = ThisTimeLineID ;
5652
- uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
5653
5732
5654
5733
if (info == XLOG_CHECKPOINT_SHUTDOWN )
5655
5734
{
@@ -5717,12 +5796,21 @@ StartupXLOG(void)
5717
5796
/* Allow read-only connections if we're consistent now */
5718
5797
CheckRecoveryConsistency ();
5719
5798
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
+ }
5726
5814
5727
5815
/* Exit loop if we reached inclusive recovery target */
5728
5816
if (!recoveryContinue )
@@ -6059,6 +6147,12 @@ StartupXLOG(void)
6059
6147
true);
6060
6148
}
6061
6149
6150
+ /*
6151
+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
6152
+ */
6153
+ if (ArchiveRecoveryRequested )
6154
+ RemoveNonParentXlogFiles (EndOfLog , ThisTimeLineID );
6155
+
6062
6156
/*
6063
6157
* Preallocate additional log files, if wanted.
6064
6158
*/
0 commit comments