@@ -782,6 +782,8 @@ static intemode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
782
782
static void XLogFileClose (void );
783
783
static void PreallocXlogFiles (XLogRecPtr endptr );
784
784
static void RemoveOldXlogFiles (XLogSegNo segno ,XLogRecPtr endptr );
785
+ static void RemoveXlogFile (const char * segname ,XLogRecPtr endptr );
786
+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint ,TimeLineID newTLI );
785
787
static void UpdateLastRemovedPtr (char * filename );
786
788
static void ValidateXLOGDirectoryStructure (void );
787
789
static void CleanupBackupHistory (void );
@@ -3743,32 +3745,17 @@ UpdateLastRemovedPtr(char *filename)
3743
3745
}
3744
3746
3745
3747
/*
3746
- * Recycle or remove all log files older or equal to passed segno
3748
+ * Recycle or remove all log files older or equal to passed segno.
3747
3749
*
3748
3750
* endptr is current (or recent) end of xlog; this is used to determine
3749
3751
* whether we want to recycle rather than delete no-longer-wanted log files.
3750
3752
*/
3751
3753
static void
3752
3754
RemoveOldXlogFiles (XLogSegNo segno ,XLogRecPtr endptr )
3753
3755
{
3754
- XLogSegNo endlogSegNo ;
3755
- int max_advance ;
3756
3756
DIR * xldir ;
3757
3757
struct dirent * xlde ;
3758
3758
char lastoff [MAXFNAMELEN ];
3759
- char path [MAXPGPATH ];
3760
-
3761
- #ifdef WIN32
3762
- char newpath [MAXPGPATH ];
3763
- #endif
3764
- struct stat statbuf ;
3765
-
3766
- /*
3767
- * Initialize info about where to try to recycle to. We allow recycling
3768
- * segments up to XLOGfileslop segments beyond the current XLOG location.
3769
- */
3770
- XLByteToPrevSeg (endptr ,endlogSegNo );
3771
- max_advance = XLOGfileslop ;
3772
3759
3773
3760
xldir = AllocateDir (XLOGDIR );
3774
3761
if (xldir == NULL )
@@ -3789,6 +3776,11 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
3789
3776
3790
3777
while ((xlde = ReadDir (xldir ,XLOGDIR ))!= NULL )
3791
3778
{
3779
+ /* Ignore files that are not XLOG segments */
3780
+ if (strlen (xlde -> d_name )!= 24 ||
3781
+ strspn (xlde -> d_name ,"0123456789ABCDEF" )!= 24 )
3782
+ continue ;
3783
+
3792
3784
/*
3793
3785
* We ignore the timeline part of the XLOG segment identifiers in
3794
3786
* deciding whether a segment is still needed. This ensures that we
@@ -3800,92 +3792,110 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr endptr)
3800
3792
* We use the alphanumeric sorting property of the filenames to decide
3801
3793
* which ones are earlier than the lastoff segment.
3802
3794
*/
3803
- if (strlen (xlde -> d_name )== 24 &&
3804
- strspn (xlde -> d_name ,"0123456789ABCDEF" )== 24 &&
3805
- strcmp (xlde -> d_name + 8 ,lastoff + 8 ) <=0 )
3795
+ if (strcmp (xlde -> d_name + 8 ,lastoff + 8 ) <=0 )
3806
3796
{
3807
3797
if (XLogArchiveCheckDone (xlde -> d_name ))
3808
3798
{
3809
- snprintf (path ,MAXPGPATH ,XLOGDIR "/%s" ,xlde -> d_name );
3810
-
3811
3799
/* Update the last removed location in shared memory first */
3812
3800
UpdateLastRemovedPtr (xlde -> d_name );
3813
3801
3814
- /*
3815
- * Before deleting the file, see if it can be recycled as a
3816
- * future log segment. Only recycle normal files, pg_standby
3817
- * for example can create symbolic links pointing to a
3818
- * separate archive directory.
3819
- */
3820
- if (lstat (path ,& statbuf )== 0 && S_ISREG (statbuf .st_mode )&&
3821
- InstallXLogFileSegment (& endlogSegNo ,path ,
3822
- true,& max_advance , true))
3823
- {
3824
- ereport (DEBUG2 ,
3825
- (errmsg ("recycled transaction log file \"%s\"" ,
3826
- xlde -> d_name )));
3827
- CheckpointStats .ckpt_segs_recycled ++ ;
3828
- /* Needn't recheck that slot on future iterations */
3829
- if (max_advance > 0 )
3830
- {
3831
- endlogSegNo ++ ;
3832
- max_advance -- ;
3833
- }
3834
- }
3835
- else
3836
- {
3837
- /* No need for any more future segments... */
3838
- int rc ;
3802
+ RemoveXlogFile (xlde -> d_name ,endptr );
3803
+ }
3804
+ }
3805
+ }
3839
3806
3840
- ereport (DEBUG2 ,
3841
- (errmsg ("removing transaction log file \"%s\"" ,
3842
- xlde -> d_name )));
3807
+ FreeDir (xldir );
3808
+ }
3843
3809
3810
+ /*
3811
+ * Recycle or remove a log file that's no longer needed.
3812
+ *
3813
+ * endptr is current (or recent) end of xlog; this is used to determine
3814
+ * whether we want to recycle rather than delete no-longer-wanted log files.
3815
+ */
3816
+ static void
3817
+ RemoveXlogFile (const char * segname ,XLogRecPtr endptr )
3818
+ {
3819
+ char path [MAXPGPATH ];
3844
3820
#ifdef WIN32
3821
+ char newpath [MAXPGPATH ];
3822
+ #endif
3823
+ struct stat statbuf ;
3824
+ XLogSegNo endlogSegNo ;
3825
+ int max_advance ;
3845
3826
3846
- /*
3847
- * On Windows, if another process (e.g another backend)
3848
- * holds the file open in FILE_SHARE_DELETE mode, unlink
3849
- * will succeed, but the file will still show up in
3850
- * directory listing until the last handle is closed. To
3851
- * avoid confusing the lingering deleted file for a live
3852
- * WAL file that needs to be archived, rename it before
3853
- * deleting it.
3854
- *
3855
- * If another process holds the file open without
3856
- * FILE_SHARE_DELETE flag, rename will fail. We'll try
3857
- * again at the next checkpoint.
3858
- */
3859
- snprintf (newpath ,MAXPGPATH ,"%s.deleted" ,path );
3860
- if (rename (path ,newpath )!= 0 )
3861
- {
3862
- ereport (LOG ,
3863
- (errcode_for_file_access (),
3864
- errmsg ("could not rename old transaction log file \"%s\": %m" ,
3865
- path )));
3866
- continue ;
3867
- }
3868
- rc = unlink (newpath );
3827
+ /*
3828
+ * Initialize info about where to try to recycle to. We allow recycling
3829
+ * segments up to XLOGfileslop segments beyond the current XLOG location.
3830
+ */
3831
+ XLByteToPrevSeg (endptr ,endlogSegNo );
3832
+ max_advance = XLOGfileslop ;
3833
+
3834
+ snprintf (path ,MAXPGPATH ,XLOGDIR "/%s" ,segname );
3835
+
3836
+ /*
3837
+ * Before deleting the file, see if it can be recycled as a future log
3838
+ * segment. Only recycle normal files, pg_standby for example can create
3839
+ * symbolic links pointing to a separate archive directory.
3840
+ */
3841
+ if (lstat (path ,& statbuf )== 0 && S_ISREG (statbuf .st_mode )&&
3842
+ InstallXLogFileSegment (& endlogSegNo ,path ,
3843
+ true,& max_advance , true))
3844
+ {
3845
+ ereport (DEBUG2 ,
3846
+ (errmsg ("recycled transaction log file \"%s\"" ,segname )));
3847
+ CheckpointStats .ckpt_segs_recycled ++ ;
3848
+ /* Needn't recheck that slot on future iterations */
3849
+ if (max_advance > 0 )
3850
+ {
3851
+ endlogSegNo ++ ;
3852
+ max_advance -- ;
3853
+ }
3854
+ }
3855
+ else
3856
+ {
3857
+ /* No need for any more future segments... */
3858
+ int rc ;
3859
+
3860
+ ereport (DEBUG2 ,
3861
+ (errmsg ("removing transaction log file \"%s\"" ,segname )));
3862
+
3863
+ #ifdef WIN32
3864
+ /*
3865
+ * On Windows, if another process (e.g another backend) holds the file
3866
+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3867
+ * will still show up in directory listing until the last handle is
3868
+ * closed. To avoid confusing the lingering deleted file for a live
3869
+ * WAL file that needs to be archived, rename it before deleting it.
3870
+ *
3871
+ * If another process holds the file open without FILE_SHARE_DELETE
3872
+ * flag, rename will fail. We'll try again at the next checkpoint.
3873
+ */
3874
+ snprintf (newpath ,MAXPGPATH ,"%s.deleted" ,path );
3875
+ if (rename (path ,newpath )!= 0 )
3876
+ {
3877
+ ereport (LOG ,
3878
+ (errcode_for_file_access (),
3879
+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3880
+ path )));
3881
+ return ;
3882
+ }
3883
+ rc = unlink (newpath );
3869
3884
#else
3870
- rc = unlink (path );
3885
+ rc = unlink (path );
3871
3886
#endif
3872
- if (rc != 0 )
3873
- {
3874
- ereport (LOG ,
3875
- (errcode_for_file_access (),
3876
- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3877
- path )));
3878
- continue ;
3879
- }
3880
- CheckpointStats .ckpt_segs_removed ++ ;
3881
- }
3882
-
3883
- XLogArchiveCleanup (xlde -> d_name );
3884
- }
3887
+ if (rc != 0 )
3888
+ {
3889
+ ereport (LOG ,
3890
+ (errcode_for_file_access (),
3891
+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3892
+ path )));
3893
+ return ;
3885
3894
}
3895
+ CheckpointStats .ckpt_segs_removed ++ ;
3886
3896
}
3887
3897
3888
- FreeDir ( xldir );
3898
+ XLogArchiveCleanup ( segname );
3889
3899
}
3890
3900
3891
3901
/*
@@ -5407,6 +5417,76 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
5407
5417
(errmsg ("archive recovery complete" )));
5408
5418
}
5409
5419
5420
+ /*
5421
+ * Remove WAL files that are not part of the given timeline's history.
5422
+ *
5423
+ * This is called during recovery, whenever we switch to follow a new
5424
+ * timeline, and at the end of recovery when we create a new timeline. We
5425
+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
5426
+ * can be pre-allocated or recycled WAL segments on the old timeline that we
5427
+ * haven't used yet, and contain garbage. If we just leave them in pg_xlog,
5428
+ * they will eventually be archived, and we can't let that happen. Files that
5429
+ * belong to our timeline history are valid, because we have successfully
5430
+ * replayed them, but from others we can't be sure.
5431
+ *
5432
+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
5433
+ * and 'newTLI' is the new timeline we switch to.
5434
+ */
5435
+ static void
5436
+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint ,TimeLineID newTLI )
5437
+ {
5438
+ DIR * xldir ;
5439
+ struct dirent * xlde ;
5440
+ char switchseg [MAXFNAMELEN ];
5441
+ XLogSegNo endLogSegNo ;
5442
+
5443
+ XLByteToPrevSeg (switchpoint ,endLogSegNo );
5444
+
5445
+ xldir = AllocateDir (XLOGDIR );
5446
+ if (xldir == NULL )
5447
+ ereport (ERROR ,
5448
+ (errcode_for_file_access (),
5449
+ errmsg ("could not open transaction log directory \"%s\": %m" ,
5450
+ XLOGDIR )));
5451
+
5452
+ /*
5453
+ * Construct a filename of the last segment to be kept.
5454
+ */
5455
+ XLogFileName (switchseg ,newTLI ,endLogSegNo );
5456
+
5457
+ elog (DEBUG2 ,"attempting to remove WAL segments newer than log file %s" ,
5458
+ switchseg );
5459
+
5460
+ while ((xlde = ReadDir (xldir ,XLOGDIR ))!= NULL )
5461
+ {
5462
+ /* Ignore files that are not XLOG segments */
5463
+ if (strlen (xlde -> d_name )!= 24 ||
5464
+ strspn (xlde -> d_name ,"0123456789ABCDEF" )!= 24 )
5465
+ continue ;
5466
+
5467
+ /*
5468
+ * Remove files that are on a timeline older than the new one we're
5469
+ * switching to, but with a segment number >= the first segment on
5470
+ * the new timeline.
5471
+ */
5472
+ if (strncmp (xlde -> d_name ,switchseg ,8 )< 0 &&
5473
+ strcmp (xlde -> d_name + 8 ,switchseg + 8 )> 0 )
5474
+ {
5475
+ /*
5476
+ * If the file has already been marked as .ready, however, don't
5477
+ * remove it yet. It should be OK to remove it - files that are
5478
+ * not part of our timeline history are not required for recovery
5479
+ * - but seems safer to let them be archived and removed later.
5480
+ */
5481
+ if (!XLogArchiveIsReady (xlde -> d_name ))
5482
+ RemoveXlogFile (xlde -> d_name ,switchpoint );
5483
+ }
5484
+ }
5485
+
5486
+ FreeDir (xldir );
5487
+ }
5488
+
5489
+
5410
5490
/*
5411
5491
* Extract timestamp from WAL record.
5412
5492
*
@@ -6775,9 +6855,9 @@ StartupXLOG(void)
6775
6855
*/
6776
6856
if (record -> xl_rmid == RM_XLOG_ID )
6777
6857
{
6858
+ uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
6778
6859
TimeLineID newTLI = ThisTimeLineID ;
6779
6860
TimeLineID prevTLI = ThisTimeLineID ;
6780
- uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
6781
6861
6782
6862
if (info == XLOG_CHECKPOINT_SHUTDOWN )
6783
6863
{
@@ -6845,12 +6925,21 @@ StartupXLOG(void)
6845
6925
/* Allow read-only connections if we're consistent now */
6846
6926
CheckRecoveryConsistency ();
6847
6927
6848
- /*
6849
- * If this record was a timeline switch, wake up any
6850
- * walsenders to notice that we are on a new timeline.
6851
- */
6852
- if (switchedTLI && AllowCascadeReplication ())
6853
- WalSndWakeup ();
6928
+ if (switchedTLI )
6929
+ {
6930
+ /*
6931
+ * Before we go further on the new timeline, clean up any
6932
+ * (possibly bogus) future WAL segments on the old one.
6933
+ */
6934
+ RemoveNonParentXlogFiles (EndRecPtr ,ThisTimeLineID );
6935
+
6936
+ /*
6937
+ * Wake up any walsenders to notice that we are on a new
6938
+ * timeline.
6939
+ */
6940
+ if (AllowCascadeReplication ())
6941
+ WalSndWakeup ();
6942
+ }
6854
6943
6855
6944
/* Exit loop if we reached inclusive recovery target */
6856
6945
if (recoveryStopsAfter (record ))
@@ -7177,6 +7266,12 @@ StartupXLOG(void)
7177
7266
true);
7178
7267
}
7179
7268
7269
+ /*
7270
+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
7271
+ */
7272
+ if (ArchiveRecoveryRequested )
7273
+ RemoveNonParentXlogFiles (EndOfLog ,ThisTimeLineID );
7274
+
7180
7275
/*
7181
7276
* Preallocate additional log files, if wanted.
7182
7277
*/