81
71
repo_reconciler = self.repo.reconcile(thorough=True)
82
72
self.inconsistent_parents = repo_reconciler.inconsistent_parents
83
73
self.garbage_inventories = repo_reconciler.garbage_inventories
84
if repo_reconciler.aborted:
86
'Reconcile aborted: revision index has inconsistent parents.')
88
'Run "bzr check" for more details.')
90
self.pb.note('Reconciliation complete.')
74
self.pb.note('Reconciliation complete.')
93
77
class RepoReconciler(object):
94
78
"""Reconciler that reconciles a repository.
96
The goal of repository reconciliation is to make any derived data
97
consistent with the core data committed by a user. This can involve
98
reindexing, or removing unreferenced data if that can interfere with
99
queries in a given repository.
101
80
Currently this consists of an inventory reweave with revision cross-checks.
192
170
# This is done to avoid a revision_count * time-to-write additional overhead on
194
172
new_inventory_vf._check_write_ok()
195
Weave._add_lines(new_inventory_vf, rev_id, parents,
196
self.inventory.get_lines(rev_id), None, None, None, False, True)
173
Weave._add_lines(new_inventory_vf, rev_id, parents, self.inventory.get_lines(rev_id),
198
176
new_inventory_vf.add_lines(rev_id, parents, self.inventory.get_lines(rev_id))
289
267
class KnitReconciler(RepoReconciler):
290
268
"""Reconciler that reconciles a knit format repository.
292
This will detect garbage inventories and remove them in thorough mode.
270
This will detect garbage inventories and remove them.
272
Inconsistent parentage is checked for in the revision weave.
295
275
def _reconcile_steps(self):
296
276
"""Perform the steps to reconcile this repository."""
297
277
if self.thorough:
300
except errors.BzrCheckError:
303
279
# knits never suffer this
304
280
self._gc_inventory()
305
self._fix_text_parents()
307
282
def _load_indexes(self):
308
283
"""Load indexes for the reconciliation."""
310
285
self.pb.update('Reading indexes.', 0, 2)
311
286
self.inventory = self.repo.get_inventory_weave()
312
287
self.pb.update('Reading indexes.', 1, 2)
313
self.repo._check_for_inconsistent_revision_parents()
314
288
self.revisions = self.repo._revision_store.get_revision_file(self.transaction)
315
289
self.pb.update('Reading indexes.', 2, 2)
363
337
self.garbage_inventories = len(garbage)
364
338
for revision_id in garbage:
365
339
mutter('Garbage inventory {%s} found.', revision_id)
367
def _fix_text_parents(self):
368
"""Fix bad versionedfile parent entries.
370
It is possible for the parents entry in a versionedfile entry to be
371
inconsistent with the values in the revision and inventory.
373
This method finds entries with such inconsistencies, corrects their
374
parent lists, and replaces the versionedfile with a corrected version.
376
transaction = self.repo.get_transaction()
377
revision_versions = repository._RevisionTextVersionCache(self.repo)
378
versions = self.revisions.versions()
379
revision_versions.prepopulate_revs(versions)
380
for num, file_id in enumerate(self.repo.weave_store):
381
self.pb.update('Fixing text parents', num,
382
len(self.repo.weave_store))
383
vf = self.repo.weave_store.get_weave(file_id, transaction)
384
vf_checker = self.repo.get_versioned_file_checker(
385
versions, revision_versions)
386
versions_with_bad_parents = vf_checker.check_file_version_parents(
388
if len(versions_with_bad_parents) == 0:
390
self._fix_text_parent(file_id, vf, versions_with_bad_parents)
392
def _fix_text_parent(self, file_id, vf, versions_with_bad_parents):
393
"""Fix bad versionedfile entries in a single versioned file."""
394
new_vf = self.repo.weave_store.get_empty('temp:%s' % file_id,
397
for version in vf.versions():
398
if version in versions_with_bad_parents:
399
parents = versions_with_bad_parents[version][1]
401
parents = vf.get_parents(version)
402
new_parents[version] = parents
403
for version in TopoSorter(new_parents.items()).iter_topo_order():
404
new_vf.add_lines(version, new_parents[version],
405
vf.get_lines(version))
406
self.repo.weave_store.copy(new_vf, file_id, self.transaction)
407
self.repo.weave_store.delete('temp:%s' % file_id, self.transaction)
410
class PackReconciler(RepoReconciler):
411
"""Reconciler that reconciles a pack based repository.
413
Garbage inventories do not affect ancestry queries, and removal is
414
considerably more expensive as there is no separate versioned file for
415
them, so they are not cleaned. In short it is currently a no-op.
417
In future this may be a good place to hook in annotation cache checking,
418
index recreation etc.
421
# XXX: The index corruption that _fix_text_parents performs is needed for
422
# packs, but not yet implemented. The basic approach is to:
423
# - lock the names list
424
# - perform a customised pack() that regenerates data as needed
425
# - unlock the names list
426
# https://bugs.edge.launchpad.net/bzr/+bug/154173
428
def _reconcile_steps(self):
429
"""Perform the steps to reconcile this repository."""