@@ -564,6 +564,7 @@ static void XLogArchiveNotify(const char *xlog);
564
564
static void XLogArchiveNotifySeg (uint32 log , uint32 seg );
565
565
static bool XLogArchiveCheckDone (const char * xlog );
566
566
static bool XLogArchiveIsBusy (const char * xlog );
567
+ extern bool XLogArchiveIsReady (const char * xlog );
567
568
static void XLogArchiveCleanup (const char * xlog );
568
569
static void readRecoveryCommandFile (void );
569
570
static void exitArchiveRecovery (TimeLineID endTLI ,
@@ -598,6 +599,8 @@ static void ExecuteRecoveryCommand(char *command, char *commandName,
598
599
bool failOnerror );
599
600
static void PreallocXlogFiles (XLogRecPtr endptr );
600
601
static void RemoveOldXlogFiles (uint32 log , uint32 seg , XLogRecPtr endptr );
602
+ static void RemoveXlogFile (const char * segname , XLogRecPtr endptr );
603
+ static void RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI );
601
604
static void UpdateLastRemovedPtr (char * filename );
602
605
static void ValidateXLOGDirectoryStructure (void );
603
606
static void CleanupBackupHistory (void );
@@ -1405,6 +1408,25 @@ XLogArchiveIsBusy(const char *xlog)
1405
1408
return true;
1406
1409
}
1407
1410
1411
+ /*
1412
+ * XLogArchiveIsReady
1413
+ *
1414
+ * Check to see if an XLOG segment file has an archive notification (.ready)
1415
+ * file.
1416
+ */
1417
+ bool
1418
+ XLogArchiveIsReady (const char * xlog )
1419
+ {
1420
+ char archiveStatusPath [MAXPGPATH ];
1421
+ struct stat stat_buf ;
1422
+
1423
+ StatusFilePath (archiveStatusPath , xlog , ".ready" );
1424
+ if (stat (archiveStatusPath , & stat_buf ) == 0 )
1425
+ return true;
1426
+
1427
+ return false;
1428
+ }
1429
+
1408
1430
/*
1409
1431
* XLogArchiveCleanup
1410
1432
*
@@ -3274,25 +3296,9 @@ UpdateLastRemovedPtr(char *filename)
3274
3296
static void
3275
3297
RemoveOldXlogFiles (uint32 log , uint32 seg , XLogRecPtr endptr )
3276
3298
{
3277
- uint32 endlogId ;
3278
- uint32 endlogSeg ;
3279
- int max_advance ;
3280
3299
DIR * xldir ;
3281
3300
struct dirent * xlde ;
3282
3301
char lastoff [MAXFNAMELEN ];
3283
- char path [MAXPGPATH ];
3284
-
3285
- #ifdef WIN32
3286
- char newpath [MAXPGPATH ];
3287
- #endif
3288
- struct stat statbuf ;
3289
-
3290
- /*
3291
- * Initialize info about where to try to recycle to. We allow recycling
3292
- * segments up to XLOGfileslop segments beyond the current XLOG location.
3293
- */
3294
- XLByteToPrevSeg (endptr , endlogId , endlogSeg );
3295
- max_advance = XLOGfileslop ;
3296
3302
3297
3303
xldir = AllocateDir (XLOGDIR );
3298
3304
if (xldir == NULL )
@@ -3308,6 +3314,11 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3308
3314
3309
3315
while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
3310
3316
{
3317
+ /* Ignore files that are not XLOG segments */
3318
+ if (strlen (xlde -> d_name ) != 24 ||
3319
+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
3320
+ continue ;
3321
+
3311
3322
/*
3312
3323
* We ignore the timeline part of the XLOG segment identifiers in
3313
3324
* deciding whether a segment is still needed. This ensures that we
@@ -3319,9 +3330,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3319
3330
* We use the alphanumeric sorting property of the filenames to decide
3320
3331
* which ones are earlier than the lastoff segment.
3321
3332
*/
3322
- if (strlen (xlde -> d_name ) == 24 &&
3323
- strspn (xlde -> d_name , "0123456789ABCDEF" ) == 24 &&
3324
- strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
3333
+ if (strcmp (xlde -> d_name + 8 , lastoff + 8 ) <= 0 )
3325
3334
{
3326
3335
/*
3327
3336
* Normally we don't delete old XLOG files during recovery to
@@ -3336,86 +3345,107 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
3336
3345
*/
3337
3346
if (WalRcvInProgress () || XLogArchiveCheckDone (xlde -> d_name ))
3338
3347
{
3339
- snprintf (path , MAXPGPATH , XLOGDIR "/%s" , xlde -> d_name );
3340
-
3341
3348
/* Update the last removed location in shared memory first */
3342
3349
UpdateLastRemovedPtr (xlde -> d_name );
3343
3350
3344
- /*
3345
- * Before deleting the file, see if it can be recycled as a
3346
- * future log segment. Only recycle normal files, pg_standby
3347
- * for example can create symbolic links pointing to a
3348
- * separate archive directory.
3349
- */
3350
- if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3351
- InstallXLogFileSegment (& endlogId , & endlogSeg , path ,
3352
- true, & max_advance , true))
3353
- {
3354
- ereport (DEBUG2 ,
3355
- (errmsg ("recycled transaction log file \"%s\"" ,
3356
- xlde -> d_name )));
3357
- CheckpointStats .ckpt_segs_recycled ++ ;
3358
- /* Needn't recheck that slot on future iterations */
3359
- if (max_advance > 0 )
3360
- {
3361
- NextLogSeg (endlogId , endlogSeg );
3362
- max_advance -- ;
3363
- }
3364
- }
3365
- else
3366
- {
3367
- /* No need for any more future segments... */
3368
- int rc ;
3351
+ RemoveXlogFile (xlde -> d_name , endptr );
3352
+ }
3353
+ }
3354
+ }
3369
3355
3370
- ereport (DEBUG2 ,
3371
- (errmsg ("removing transaction log file \"%s\"" ,
3372
- xlde -> d_name )));
3356
+ FreeDir (xldir );
3357
+ }
3373
3358
3359
+ /*
3360
+ * Recycle or remove a log file that's no longer needed.
3361
+ *
3362
+ * endptr is current (or recent) end of xlog; this is used to determine
3363
+ * whether we want to recycle rather than delete no-longer-wanted log files.
3364
+ */
3365
+ static void
3366
+ RemoveXlogFile (const char * segname , XLogRecPtr endptr )
3367
+ {
3368
+ char path [MAXPGPATH ];
3374
3369
#ifdef WIN32
3370
+ char newpath [MAXPGPATH ];
3371
+ #endif
3372
+ struct stat statbuf ;
3373
+ uint32 endlogId ;
3374
+ uint32 endlogSeg ;
3375
+ int max_advance ;
3375
3376
3376
- /*
3377
- * On Windows, if another process (e.g another backend)
3378
- * holds the file open in FILE_SHARE_DELETE mode, unlink
3379
- * will succeed, but the file will still show up in
3380
- * directory listing until the last handle is closed. To
3381
- * avoid confusing the lingering deleted file for a live
3382
- * WAL file that needs to be archived, rename it before
3383
- * deleting it.
3384
- *
3385
- * If another process holds the file open without
3386
- * FILE_SHARE_DELETE flag, rename will fail. We'll try
3387
- * again at the next checkpoint.
3388
- */
3389
- snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3390
- if (rename (path , newpath ) != 0 )
3391
- {
3392
- ereport (LOG ,
3393
- (errcode_for_file_access (),
3394
- errmsg ("could not rename old transaction log file \"%s\": %m" ,
3395
- path )));
3396
- continue ;
3397
- }
3398
- rc = unlink (newpath );
3377
+ /*
3378
+ * Initialize info about where to try to recycle to. We allow recycling
3379
+ * segments up to XLOGfileslop segments beyond the current XLOG location.
3380
+ */
3381
+ XLByteToPrevSeg (endptr , endlogId , endlogSeg );
3382
+ max_advance = XLOGfileslop ;
3383
+
3384
+ snprintf (path , MAXPGPATH , XLOGDIR "/%s" , segname );
3385
+
3386
+ /*
3387
+ * Before deleting the file, see if it can be recycled as a future log
3388
+ * segment. Only recycle normal files, pg_standby for example can create
3389
+ * symbolic links pointing to a separate archive directory.
3390
+ */
3391
+ if (lstat (path , & statbuf ) == 0 && S_ISREG (statbuf .st_mode ) &&
3392
+ InstallXLogFileSegment (& endlogId , & endlogSeg , path ,
3393
+ true, & max_advance , true))
3394
+ {
3395
+ ereport (DEBUG2 ,
3396
+ (errmsg ("recycled transaction log file \"%s\"" , segname )));
3397
+ CheckpointStats .ckpt_segs_recycled ++ ;
3398
+ /* Needn't recheck that slot on future iterations */
3399
+ if (max_advance > 0 )
3400
+ {
3401
+ NextLogSeg (endlogId , endlogSeg );
3402
+ max_advance -- ;
3403
+ }
3404
+ }
3405
+ else
3406
+ {
3407
+ /* No need for any more future segments... */
3408
+ int rc ;
3409
+
3410
+ ereport (DEBUG2 ,
3411
+ (errmsg ("removing transaction log file \"%s\"" , segname )));
3412
+
3413
+ #ifdef WIN32
3414
+ /*
3415
+ * On Windows, if another process (e.g another backend) holds the file
3416
+ * open in FILE_SHARE_DELETE mode, unlink will succeed, but the file
3417
+ * will still show up in directory listing until the last handle is
3418
+ * closed. To avoid confusing the lingering deleted file for a live
3419
+ * WAL file that needs to be archived, rename it before deleting it.
3420
+ *
3421
+ * If another process holds the file open without FILE_SHARE_DELETE
3422
+ * flag, rename will fail. We'll try again at the next checkpoint.
3423
+ */
3424
+ snprintf (newpath , MAXPGPATH , "%s.deleted" , path );
3425
+ if (rename (path , newpath ) != 0 )
3426
+ {
3427
+ ereport (LOG ,
3428
+ (errcode_for_file_access (),
3429
+ errmsg ("could not rename old transaction log file \"%s\": %m" ,
3430
+ path )));
3431
+ return ;
3432
+ }
3433
+ rc = unlink (newpath );
3399
3434
#else
3400
- rc = unlink (path );
3435
+ rc = unlink (path );
3401
3436
#endif
3402
- if (rc != 0 )
3403
- {
3404
- ereport (LOG ,
3405
- (errcode_for_file_access (),
3406
- errmsg ("could not remove old transaction log file \"%s\": %m" ,
3407
- path )));
3408
- continue ;
3409
- }
3410
- CheckpointStats .ckpt_segs_removed ++ ;
3411
- }
3412
-
3413
- XLogArchiveCleanup (xlde -> d_name );
3414
- }
3437
+ if (rc != 0 )
3438
+ {
3439
+ ereport (LOG ,
3440
+ (errcode_for_file_access (),
3441
+ errmsg ("could not remove old transaction log file \"%s\": %m" ,
3442
+ path )));
3443
+ return ;
3415
3444
}
3445
+ CheckpointStats .ckpt_segs_removed ++ ;
3416
3446
}
3417
3447
3418
- FreeDir ( xldir );
3448
+ XLogArchiveCleanup ( segname );
3419
3449
}
3420
3450
3421
3451
/*
@@ -5501,6 +5531,76 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
5501
5531
(errmsg ("archive recovery complete" )));
5502
5532
}
5503
5533
5534
+ /*
5535
+ * Remove WAL files that are not part of the given timeline's history.
5536
+ *
5537
+ * This is called during recovery, whenever we switch to follow a new
5538
+ * timeline, and at the end of recovery when we create a new timeline. We
5539
+ * wouldn't otherwise care about extra WAL files lying in pg_xlog, but they
5540
+ * can be pre-allocated or recycled WAL segments on the old timeline that we
5541
+ * haven't used yet, and contain garbage. If we just leave them in pg_xlog,
5542
+ * they will eventually be archived, and we can't let that happen. Files that
5543
+ * belong to our timeline history are valid, because we have successfully
5544
+ * replayed them, but from others we can't be sure.
5545
+ *
5546
+ * 'switchpoint' is the current point in WAL where we switch to new timeline,
5547
+ * and 'newTLI' is the new timeline we switch to.
5548
+ */
5549
+ static void
5550
+ RemoveNonParentXlogFiles (XLogRecPtr switchpoint , TimeLineID newTLI )
5551
+ {
5552
+ DIR * xldir ;
5553
+ struct dirent * xlde ;
5554
+ char switchseg [MAXFNAMELEN ];
5555
+ uint32 endlogId ;
5556
+ uint32 endlogSeg ;
5557
+
5558
+ XLByteToPrevSeg (switchpoint , endlogId , endlogSeg );
5559
+
5560
+ xldir = AllocateDir (XLOGDIR );
5561
+ if (xldir == NULL )
5562
+ ereport (ERROR ,
5563
+ (errcode_for_file_access (),
5564
+ errmsg ("could not open transaction log directory \"%s\": %m" ,
5565
+ XLOGDIR )));
5566
+
5567
+ /*
5568
+ * Construct a filename of the last segment to be kept.
5569
+ */
5570
+ XLogFileName (switchseg , newTLI , endlogId , endlogSeg );
5571
+
5572
+ elog (DEBUG2 , "attempting to remove WAL segments newer than log file %s" ,
5573
+ switchseg );
5574
+
5575
+ while ((xlde = ReadDir (xldir , XLOGDIR )) != NULL )
5576
+ {
5577
+ /* Ignore files that are not XLOG segments */
5578
+ if (strlen (xlde -> d_name ) != 24 ||
5579
+ strspn (xlde -> d_name , "0123456789ABCDEF" ) != 24 )
5580
+ continue ;
5581
+
5582
+ /*
5583
+ * Remove files that are on a timeline older than the new one we're
5584
+ * switching to, but with a segment number >= the first segment on
5585
+ * the new timeline.
5586
+ */
5587
+ if (strncmp (xlde -> d_name , switchseg , 8 ) < 0 &&
5588
+ strcmp (xlde -> d_name + 8 , switchseg + 8 ) > 0 )
5589
+ {
5590
+ /*
5591
+ * If the file has already been marked as .ready, however, don't
5592
+ * remove it yet. It should be OK to remove it - files that are
5593
+ * not part of our timeline history are not required for recovery
5594
+ * - but seems safer to let them be archived and removed later.
5595
+ */
5596
+ if (!XLogArchiveIsReady (xlde -> d_name ))
5597
+ RemoveXlogFile (xlde -> d_name , switchpoint );
5598
+ }
5599
+ }
5600
+
5601
+ FreeDir (xldir );
5602
+ }
5603
+
5504
5604
/*
5505
5605
* For point-in-time recovery, this function decides whether we want to
5506
5606
* stop applying the XLOG at or after the current record.
@@ -5771,6 +5871,7 @@ StartupXLOG(void)
5771
5871
bool wasShutdown ;
5772
5872
bool reachedStopPoint = false;
5773
5873
bool haveBackupLabel = false;
5874
+ bool didArchiveRecovery = false;
5774
5875
XLogRecPtr RecPtr ,
5775
5876
checkPointLoc ,
5776
5877
EndOfLog ;
@@ -6469,7 +6570,10 @@ StartupXLOG(void)
6469
6570
* we will use that below.)
6470
6571
*/
6471
6572
if (InArchiveRecovery )
6573
+ {
6574
+ didArchiveRecovery = true;
6472
6575
exitArchiveRecovery (curFileTLI , endLogId , endLogSeg );
6576
+ }
6473
6577
6474
6578
/*
6475
6579
* Prepare to write WAL starting at EndOfLog position, and init xlog
@@ -6582,6 +6686,12 @@ StartupXLOG(void)
6582
6686
true);
6583
6687
}
6584
6688
6689
+ /*
6690
+ * Clean up any (possibly bogus) future WAL segments on the old timeline.
6691
+ */
6692
+ if (didArchiveRecovery )
6693
+ RemoveNonParentXlogFiles (EndOfLog , ThisTimeLineID );
6694
+
6585
6695
/*
6586
6696
* Preallocate additional log files, if wanted.
6587
6697
*/
0 commit comments