@@ -609,6 +609,7 @@ static void XLogArchiveNotify(const char *xlog);
609
609
static void XLogArchiveNotifySeg (uint32 log ,uint32 seg );
610
610
static bool XLogArchiveCheckDone (const char * xlog );
611
611
static bool XLogArchiveIsBusy (const char * xlog );
612
+ extern bool XLogArchiveIsReady (const char * xlog );
612
613
static void XLogArchiveCleanup (const char * xlog );
613
614
static void readRecoveryCommandFile (void );
614
615
static void exitArchiveRecovery (TimeLineID endTLI ,
@@ -646,6 +647,8 @@ static void ExecuteRecoveryCommand(char *command, char *commandName,
646
647
bool failOnerror );
647
648
static void PreallocXlogFiles (XLogRecPtr endptr );
648
649
static 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 );
649
652
static void UpdateLastRemovedPtr (char * filename );
650
653
static void ValidateXLOGDirectoryStructure (void );
651
654
static void CleanupBackupHistory (void );
@@ -1455,6 +1458,25 @@ XLogArchiveIsBusy(const char *xlog)
1455
1458
return true;
1456
1459
}
1457
1460
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
+
1458
1480
/*
1459
1481
* XLogArchiveCleanup
1460
1482
*
@@ -3332,25 +3354,9 @@ UpdateLastRemovedPtr(char *filename)
3332
3354
static void
3333
3355
RemoveOldXlogFiles (uint32 log ,uint32 seg ,XLogRecPtr endptr )
3334
3356
{
3335
- uint32 endlogId ;
3336
- uint32 endlogSeg ;
3337
- int max_advance ;
3338
3357
DIR * xldir ;
3339
3358
struct dirent * xlde ;
3340
3359
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 ;
3354
3360
3355
3361
xldir = AllocateDir (XLOGDIR );
3356
3362
if (xldir == NULL )
@@ -3366,6 +3372,11 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3366
3372
3367
3373
while ((xlde = ReadDir (xldir ,XLOGDIR ))!= NULL )
3368
3374
{
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
+
3369
3380
/*
3370
3381
* We ignore the timeline part of the XLOG segment identifiers in
3371
3382
* deciding whether a segment is still needed. This ensures that we
@@ -3377,9 +3388,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3377
3388
* We use the alphanumeric sorting property of the filenames to decide
3378
3389
* which ones are earlier than the lastoff segment.
3379
3390
*/
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 )
3383
3392
{
3384
3393
/*
3385
3394
* Normally we don't delete old XLOG files during recovery to
@@ -3394,86 +3403,107 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3394
3403
*/
3395
3404
if (WalRcvInProgress ()|| XLogArchiveCheckDone (xlde -> d_name ))
3396
3405
{
3397
- snprintf (path ,MAXPGPATH ,XLOGDIR "/%s" ,xlde -> d_name );
3398
-
3399
3406
/* Update the last removed location in shared memory first */
3400
3407
UpdateLastRemovedPtr (xlde -> d_name );
3401
3408
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
+ }
3427
3413
3428
- ereport (DEBUG2 ,
3429
- (errmsg ("removing transaction log file \"%s\"" ,
3430
- xlde -> d_name )));
3414
+ FreeDir (xldir );
3415
+ }
3431
3416
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 ];
3432
3427
#ifdef WIN32
3428
+ char newpath [MAXPGPATH ];
3429
+ #endif
3430
+ struct stat statbuf ;
3431
+ uint32 endlogId ;
3432
+ uint32 endlogSeg ;
3433
+ int max_advance ;
3433
3434
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 );
3457
3492
#else
3458
- rc = unlink (path );
3493
+ rc = unlink (path );
3459
3494
#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 ;
3473
3502
}
3503
+ CheckpointStats .ckpt_segs_removed ++ ;
3474
3504
}
3475
3505
3476
- FreeDir ( xldir );
3506
+ XLogArchiveCleanup ( segname );
3477
3507
}
3478
3508
3479
3509
/*
@@ -5629,6 +5659,76 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
5629
5659
(errmsg ("archive recovery complete" )));
5630
5660
}
5631
5661
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
+
5632
5732
/*
5633
5733
* For point-in-time recovery, this function decides whether we want to
5634
5734
* stop applying the XLOG at or after the current record.
@@ -6075,6 +6175,7 @@ StartupXLOG(void)
6075
6175
bool wasShutdown ;
6076
6176
bool reachedStopPoint = false;
6077
6177
bool haveBackupLabel = false;
6178
+ bool didArchiveRecovery = false;
6078
6179
XLogRecPtr RecPtr ,
6079
6180
checkPointLoc ,
6080
6181
EndOfLog ;
@@ -6844,7 +6945,10 @@ StartupXLOG(void)
6844
6945
* we will use that below.)
6845
6946
*/
6846
6947
if (InArchiveRecovery )
6948
+ {
6949
+ didArchiveRecovery = true;
6847
6950
exitArchiveRecovery (curFileTLI ,endLogId ,endLogSeg );
6951
+ }
6848
6952
6849
6953
/*
6850
6954
* Prepare to write WAL starting at EndOfLog position, and init xlog
@@ -6957,6 +7061,12 @@ StartupXLOG(void)
6957
7061
true);
6958
7062
}
6959
7063
7064
+ /*
7065
+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
7066
+ */
7067
+ if (didArchiveRecovery )
7068
+ RemoveNonParentXlogFiles (EndOfLog ,ThisTimeLineID );
7069
+
6960
7070
/*
6961
7071
* Preallocate additional log files, if wanted.
6962
7072
*/