From 97b5154fc56a37643c4ebb0fcf42019fcba5ccdf Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 10 Mar 2015 01:11:18 +0100 Subject: [PATCH 1/2] check: sort archives in reverse time order --- attic/archive.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/attic/archive.py b/attic/archive.py index d78ce4b85..62a4df73d 100644 --- a/attic/archive.py +++ b/attic/archive.py @@ -672,7 +672,9 @@ class ArchiveChecker: repository = cache_if_remote(self.repository) num_archives = len(self.manifest.archives) - for i, (name, info) in enumerate(list(self.manifest.archives.items()), 1): + archive_items = sorted(self.manifest.archives.items(), reverse=True, + key=lambda name_info: name_info[1][b'time']) + for i, (name, info) in enumerate(archive_items, 1): self.report_progress('Analyzing archive {} ({}/{})'.format(name, i, num_archives)) archive_id = info[b'id'] if not archive_id in self.chunks: From 90c50e3171673fab694a0f122acedbcc6996b918 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 11 Mar 2015 03:04:12 +0100 Subject: [PATCH 2/2] implement check --last N Note: of course it can only check for orphaned objects, if it has processed all archives in the repo. Thus this check is skipped as soon as you give --last N option. The numbers shown in progress indicator are (N,T). N is the number of the currently checked archive (starts at T as it first checks latest archive). T is the total number of archives. --- attic/archive.py | 16 ++++++++++------ attic/archiver.py | 5 ++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/attic/archive.py b/attic/archive.py index 62a4df73d..09b9b52c7 100644 --- a/attic/archive.py +++ b/attic/archive.py @@ -529,7 +529,7 @@ class ArchiveChecker: def __del__(self): shutil.rmtree(self.tmpdir) - def check(self, repository, repair=False): + def check(self, repository, repair=False, last=None): self.report_progress('Starting archive consistency check...') self.repair = repair self.repository = repository @@ -539,8 +539,11 @@ class ArchiveChecker: self.manifest = self.rebuild_manifest() else: self.manifest, _ = Manifest.load(repository, key=self.key) - self.rebuild_refcounts() - self.verify_chunks() + self.rebuild_refcounts(last=last) + if last is None: + self.verify_chunks() + else: + self.report_progress('Orphaned objects check skipped (needs all archives checked)') if not self.error_found: self.report_progress('Archive consistency check complete, no problems found.') return self.repair or not self.error_found @@ -595,7 +598,7 @@ class ArchiveChecker: self.report_progress('Manifest rebuild complete', error=True) return manifest - def rebuild_refcounts(self): + def rebuild_refcounts(self, last=None): """Rebuild object reference counts by walking the metadata Missing and/or incorrect data is repaired when detected @@ -674,8 +677,9 @@ class ArchiveChecker: num_archives = len(self.manifest.archives) archive_items = sorted(self.manifest.archives.items(), reverse=True, key=lambda name_info: name_info[1][b'time']) - for i, (name, info) in enumerate(archive_items, 1): - self.report_progress('Analyzing archive {} ({}/{})'.format(name, i, num_archives)) + end = None if last is None else min(num_archives, last) + for i, (name, info) in enumerate(archive_items[:end]): + self.report_progress('Analyzing archive {} ({}/{})'.format(name, num_archives - i, num_archives)) archive_id = info[b'id'] if not archive_id in self.chunks: self.report_progress('Archive metadata block is missing', error=True) diff --git a/attic/archiver.py b/attic/archiver.py index 47650c2d4..e7dc2b2e0 100644 --- a/attic/archiver.py +++ b/attic/archiver.py @@ -81,7 +81,7 @@ Type "Yes I am sure" if you understand this and want to continue.\n""") print('Repository check complete, no problems found.') else: return 1 - if not args.repo_only and not ArchiveChecker().check(repository, repair=args.repair): + if not args.repo_only and not ArchiveChecker().check(repository, repair=args.repair, last=args.last): return 1 return 0 @@ -503,6 +503,9 @@ Type "Yes I am sure" if you understand this and want to continue.\n""") subparser.add_argument('--repair', dest='repair', action='store_true', default=False, help='attempt to repair any inconsistencies found') + subparser.add_argument('--last', dest='last', + type=int, default=None, metavar='N', + help='only check last N archives (Default: all)') change_passphrase_epilog = textwrap.dedent(""" The key files used for repository encryption are optionally passphrase