2
0
Эх сурвалжийг харах

Merge pull request #941 from ThomasWaldmann/keep-last-n

implement --keep-last N via --keep-secondly N, also --keep-minutely, fixes #537
TW 9 жил өмнө
parent
commit
7ffbd4a200
1 өөрчлөгдсөн 37 нэмэгдсэн , 24 устгасан
  1. 37 24
      borg/archiver.py

+ 37 - 24
borg/archiver.py

@@ -775,10 +775,10 @@ class Archiver:
     @with_repository()
     def do_prune(self, args, repository, manifest, key):
         """Prune repository archives according to specified rules"""
-        if not any((args.hourly, args.daily,
+        if not any((args.secondly, args.minutely, args.hourly, args.daily,
                     args.weekly, args.monthly, args.yearly, args.within)):
             self.print_error('At least one of the "keep-within", "keep-last", '
-                             '"keep-hourly", "keep-daily", '
+                             '"keep-secondly", "keep-minutely", "keep-hourly", "keep-daily", '
                              '"keep-weekly", "keep-monthly" or "keep-yearly" settings must be specified.')
             return self.exit_code
         archives = manifest.list_archive_infos(sort_by='ts', reverse=True)  # just a ArchiveInfo list
@@ -787,6 +787,10 @@ class Archiver:
         keep = []
         if args.within:
             keep += prune_within(archives, args.within)
+        if args.secondly:
+            keep += prune_split(archives, '%Y-%m-%d %H:%M:%S', args.secondly, keep)
+        if args.minutely:
+            keep += prune_split(archives, '%Y-%m-%d %H:%M', args.minutely, keep)
         if args.hourly:
             keep += prune_split(archives, '%Y-%m-%d %H', args.hourly, keep)
         if args.daily:
@@ -798,21 +802,21 @@ class Archiver:
         if args.yearly:
             keep += prune_split(archives, '%Y', args.yearly, keep)
 
-        keep.sort(key=attrgetter('ts'), reverse=True)
-        to_delete = [a for a in archives if a not in keep]
+        to_delete = set(archives) - set(keep)
         stats = Statistics()
         with Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait) as cache:
-            for archive in keep:
-                if args.output_list:
-                    logger.info('Keeping archive: %s' % format_archive(archive))
-            for archive in to_delete:
-                if args.dry_run:
-                    if args.output_list:
-                        logger.info('Would prune:     %s' % format_archive(archive))
+            for archive in archives:
+                if archive in to_delete:
+                    if args.dry_run:
+                        if args.output_list:
+                            logger.info('Would prune:     %s' % format_archive(archive))
+                    else:
+                        if args.output_list:
+                            logger.info('Pruning archive: %s' % format_archive(archive))
+                        Archive(repository, key, manifest, archive.name, cache).delete(stats)
                 else:
                     if args.output_list:
-                        logger.info('Pruning archive: %s' % format_archive(archive))
-                    Archive(repository, key, manifest, archive.name, cache).delete(stats)
+                        logger.info('Keeping archive: %s' % format_archive(archive))
             if to_delete and not args.dry_run:
                 manifest.write()
                 repository.commit(save_space=args.save_space)
@@ -1587,13 +1591,10 @@ class Archiver:
         any of the specified retention options. This command is normally used by
         automated backup scripts wanting to keep a certain number of historic backups.
 
-        As an example, "-d 7" means to keep the latest backup on each day, up to 7
-        most recent days with backups (days without backups do not count).
-        The rules are applied from hourly to yearly, and backups selected by previous
-        rules do not count towards those of later rules. The time that each backup
-        completes is used for pruning purposes. Dates and times are interpreted in
-        the local timezone, and weeks go from Monday to Sunday. Specifying a
-        negative number of archives to keep means that there is no limit.
+        If a prefix is set with -P, then only archives that start with the prefix are
+        considered for deletion and only those archives count towards the totals
+        specified by the rules.
+        Otherwise, *all* archives in the repository are candidates for deletion!
 
         The "--keep-within" option takes an argument of the form "<int><char>",
         where char is "H", "d", "w", "m", "y". For example, "--keep-within 2d" means
@@ -1601,10 +1602,18 @@ class Archiver:
         "1m" is taken to mean "31d". The archives kept with this option do not
         count towards the totals specified by any other options.
 
-        If a prefix is set with -P, then only archives that start with the prefix are
-        considered for deletion and only those archives count towards the totals
-        specified by the rules.
-        Otherwise, *all* archives in the repository are candidates for deletion!
+        A good procedure is to thin out more and more the older your backups get.
+        As an example, "--keep-daily 7" means to keep the latest backup on each day,
+        up to 7 most recent days with backups (days without backups do not count).
+        The rules are applied from secondly to yearly, and backups selected by previous
+        rules do not count towards those of later rules. The time that each backup
+        completes is used for pruning purposes. Dates and times are interpreted in
+        the local timezone, and weeks go from Monday to Sunday. Specifying a
+        negative number of archives to keep means that there is no limit.
+
+        The "--keep-last N" option is doing the same as "--keep-secondly N" (and it will
+        keep the last N archives under the assumption that you do not create more than one
+        backup archive in the same second).
         """)
         subparser = subparsers.add_parser('prune', parents=[common_parser], add_help=False,
                                           description=self.do_prune.__doc__,
@@ -1623,6 +1632,10 @@ class Archiver:
                                help='output verbose list of archives it keeps/prunes')
         subparser.add_argument('--keep-within', dest='within', type=str, metavar='WITHIN',
                                help='keep all archives within this time interval')
+        subparser.add_argument('--keep-last', '--keep-secondly', dest='secondly', type=int, default=0,
+                               help='number of secondly archives to keep')
+        subparser.add_argument('--keep-minutely', dest='minutely', type=int, default=0,
+                               help='number of minutely archives to keep')
         subparser.add_argument('-H', '--keep-hourly', dest='hourly', type=int, default=0,
                                help='number of hourly archives to keep')
         subparser.add_argument('-d', '--keep-daily', dest='daily', type=int, default=0,