1414#include <time.h>
1515#include <unistd.h>
1616
17- static void delete_walfiles (XLogRecPtr keep_lsn , timelineInfo * tli ,
17+ static void delete_walfiles_in_tli (XLogRecPtr keep_lsn , timelineInfo * tli ,
1818 uint32 xlog_seg_size , bool dry_run );
1919static void do_retention_internal (parray * backup_list , parray * to_keep_list ,
2020 parray * to_purge_list );
@@ -607,10 +607,11 @@ do_retention_purge(parray *to_keep_list, parray *to_purge_list)
607607 }
608608}
609609
610- /* Purge WAL
610+ /*
611+ * Purge WAL
611612 * Iterate over timelines
612- * Look for closest_backup, if exists, goto next timelime
613- * if not exists, look for oldest backup on timeline
613+ * Look for WAL segment not reachable from existing backups
614+ * and delete them.
614615 */
615616static void
616617do_retention_wal (bool dry_run )
@@ -624,25 +625,32 @@ do_retention_wal(bool dry_run)
624625 {
625626 timelineInfo * tlinfo = (timelineInfo * ) parray_get (tli_list , i );
626627
627- /* Empty timeline can be safely skipped */
628- if (tlinfo -> n_xlog_files == 0 &&
629- parray_num (tlinfo -> xlog_filelist ) == 0 )
628+ /*
629+ * Empty timeline (only mentioned in timeline history file)
630+ * has nothing to cleanup.
631+ */
632+ if (tlinfo -> n_xlog_files == 0 && parray_num (tlinfo -> xlog_filelist ) == 0 )
630633 continue ;
631634
632- /* If closest backup is exists, then timeline can be safely skipped */
635+ /*
636+ * If closest backup exists, then timeline is reachable from
637+ * at least one backup and none files should not be removed.
638+ */
633639 if (tlinfo -> closest_backup )
634640 continue ;
635641
636642 /*
637643 * Purge all WAL segments before START LSN of oldest backup.
638- * If there is no backups on timeline , then whole timeline
644+ * If timeline doesn't have a backup , then whole timeline
639645 * can be safely purged.
646+ * Note, that oldest_backup is not necessarily valid here,
647+ * but still we keep wal for it.
640648 */
641649 if (tlinfo -> oldest_backup )
642- delete_walfiles (tlinfo -> oldest_backup -> start_lsn ,
650+ delete_walfiles_in_tli (tlinfo -> oldest_backup -> start_lsn ,
643651 tlinfo , instance_config .xlog_seg_size , dry_run );
644652 else
645- delete_walfiles (InvalidXLogRecPtr ,
653+ delete_walfiles_in_tli (InvalidXLogRecPtr ,
646654 tlinfo , instance_config .xlog_seg_size , dry_run );
647655 }
648656}
@@ -710,7 +718,8 @@ delete_backup_files(pgBackup *backup)
710718 return ;
711719}
712720
713- /* Purge WAL archive.
721+ /*
722+ * Purge WAL archive. One timeline at a time.
714723 * If 'keep_lsn' is InvalidXLogRecPtr, then whole timeline can be purged
715724 * If 'keep_lsn' is valid LSN, then every lesser segment can be purged.
716725 * If 'dry_run' is set, then don`t actually delete anything.
@@ -720,7 +729,8 @@ delete_backup_files(pgBackup *backup)
720729 * Case 2:
721730 * archive is not empty, 'keep_lsn' is valid and prevening us from deleting anything.
722731 * Case 3:
723- * archive is not empty, 'keep_lsn' is invalid, drop everyhing in archive.
732+ * archive is not empty, 'keep_lsn' is invalid, drop all WAL files in archive,
733+ * belonging to the timeline.
724734 * Case 4:
725735 * archive is empty, 'keep_lsn' is valid, assume corruption of WAL archive.
726736 * Case 5:
@@ -730,11 +740,11 @@ delete_backup_files(pgBackup *backup)
730740 * Q: Maybe we should stop treating partial WAL segments as second-class citizens?
731741 */
732742static void
733- delete_walfiles (XLogRecPtr keep_lsn , timelineInfo * tlinfo ,
743+ delete_walfiles_in_tli (XLogRecPtr keep_lsn , timelineInfo * tlinfo ,
734744 uint32 xlog_seg_size , bool dry_run )
735745{
736- XLogSegNo StartSegNo ; /* First segment to delete */
737- XLogSegNo EndSegNo = 0 ; /* Oldest segment to keep */
746+ XLogSegNo FirstToDeleteSegNo ;
747+ XLogSegNo OldestToKeepSegNo = 0 ;
738748 int rc ;
739749 int i ;
740750 int wal_size_logical = 0 ;
@@ -752,47 +762,47 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
752762 if (XLogRecPtrIsInvalid (keep_lsn ))
753763 {
754764 /* Drop all files in timeline */
755- elog (INFO , "All files on timeline %i will be removed" , tlinfo -> tli );
756- StartSegNo = tlinfo -> begin_segno ;
757- EndSegNo = tlinfo -> end_segno ;
765+ elog (INFO , "All files on timeline %i %s be removed" , tlinfo -> tli ,
766+ dry_run ?"can" :"will" );
767+ FirstToDeleteSegNo = tlinfo -> begin_segno ;
768+ OldestToKeepSegNo = tlinfo -> end_segno ;
758769 purge_all = true;
759770 }
760771 else
761772 {
762773 /* Drop all segments between begin_segno and segment with keep_lsn (excluding) */
763- StartSegNo = tlinfo -> begin_segno ;
764- GetXLogSegNo (keep_lsn , EndSegNo , xlog_seg_size );
774+ FirstToDeleteSegNo = tlinfo -> begin_segno ;
775+ GetXLogSegNo (keep_lsn , OldestToKeepSegNo , xlog_seg_size );
765776 }
766777
767- if (EndSegNo > 0 && EndSegNo > StartSegNo )
768- elog (INFO , "WAL segments between %08X%08X and %08X%08X on timeline %i will be removed" ,
769- (uint32 ) StartSegNo / xlog_seg_size , (uint32 ) StartSegNo % xlog_seg_size ,
770- (uint32 ) (EndSegNo - 1 ) / xlog_seg_size ,
771- (uint32 ) (EndSegNo - 1 ) % xlog_seg_size ,
772- tlinfo -> tli );
778+ if (OldestToKeepSegNo > 0 && OldestToKeepSegNo > FirstToDeleteSegNo )
779+ elog (INFO , "WAL segments between %08X%08X and %08X%08X on timeline %i %s be removed" ,
780+ (uint32 ) FirstToDeleteSegNo / xlog_seg_size , (uint32 ) FirstToDeleteSegNo % xlog_seg_size ,
781+ (uint32 ) (OldestToKeepSegNo - 1 ) / xlog_seg_size ,
782+ (uint32 ) (OldestToKeepSegNo - 1 ) % xlog_seg_size ,
783+ tlinfo -> tli , dry_run ? "can" : "will" );
773784
774785 /* sanity */
775- if (EndSegNo > StartSegNo )
776- /* typical scenario */
777- wal_size_logical = (EndSegNo - StartSegNo ) * xlog_seg_size ;
778- else if (EndSegNo < StartSegNo )
786+ if (OldestToKeepSegNo > FirstToDeleteSegNo )
787+ wal_size_logical = (OldestToKeepSegNo - FirstToDeleteSegNo ) * xlog_seg_size ;
788+ else if (OldestToKeepSegNo < FirstToDeleteSegNo )
779789 {
780- /* It is actually possible for EndSegNo to be less than StartSegNo
790+ /* It is actually possible for OldestToKeepSegNo to be less than FirstToDeleteSegNo
781791 * in case of :
782792 * 1. WAL archive corruption.
783793 * 2. There is no actual WAL archive to speak of and
784794 * 'keep_lsn' is coming from STREAM backup.
785795 *
786796 * Assume the worst.
787797 */
788- if (StartSegNo > 0 && EndSegNo > 0 )
798+ if (FirstToDeleteSegNo > 0 && OldestToKeepSegNo > 0 )
789799 elog (WARNING , "On timeline %i first segment %08X%08X is greater than "
790800 "oldest segment to keep %08X%08X. Possible WAL archive corruption!" ,
791801 tlinfo -> tli ,
792- (uint32 ) StartSegNo / xlog_seg_size , (uint32 ) StartSegNo % xlog_seg_size ,
793- (uint32 ) EndSegNo / xlog_seg_size , (uint32 ) EndSegNo % xlog_seg_size );
802+ (uint32 ) FirstToDeleteSegNo / xlog_seg_size , (uint32 ) FirstToDeleteSegNo % xlog_seg_size ,
803+ (uint32 ) OldestToKeepSegNo / xlog_seg_size , (uint32 ) OldestToKeepSegNo % xlog_seg_size );
794804 }
795- else if (EndSegNo == StartSegNo && !purge_all )
805+ else if (OldestToKeepSegNo == FirstToDeleteSegNo && !purge_all )
796806 {
797807 /* 'Nothing to delete' scenario because of 'keep_lsn'
798808 * with possible exception of partial and backup history files.
@@ -804,7 +814,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
804814 if (wal_size_logical > 0 )
805815 {
806816 pretty_size (wal_size_logical , wal_pretty_size , lengthof (wal_pretty_size ));
807- elog (INFO , "WAL size to remove on timeline %i: %s" ,
817+ elog (INFO , "Logical WAL size to remove on timeline %i : %s" ,
808818 tlinfo -> tli , wal_pretty_size );
809819 }
810820
@@ -813,15 +823,15 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
813823 {
814824 xlogFile * wal_file = (xlogFile * ) parray_get (tlinfo -> xlog_filelist , i );
815825
816- if (purge_all || wal_file -> segno < EndSegNo )
826+ if (purge_all || wal_file -> segno < OldestToKeepSegNo )
817827 wal_size_actual += wal_file -> file .size ;
818828 }
819829
820830 /* Report the actual size to delete */
821831 if (wal_size_actual > 0 )
822832 {
823833 pretty_size (wal_size_actual , wal_pretty_size , lengthof (wal_pretty_size ));
824- elog (INFO , "Resident data size to free on timeline %i: %s" ,
834+ elog (INFO , "Resident data size to free on timeline %i : %s" ,
825835 tlinfo -> tli , wal_pretty_size );
826836 }
827837
@@ -838,7 +848,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
838848 /* Any segment equal or greater than EndSegNo must be kept
839849 * unless it`s a 'purge all' scenario.
840850 */
841- if (purge_all || wal_file -> segno < EndSegNo )
851+ if (purge_all || wal_file -> segno < OldestToKeepSegNo )
842852 {
843853 /* unlink segment */
844854 rc = unlink (wal_file -> file .path );
0 commit comments