57
57
garbage_inventories: The number of inventory objects without revisions
58
58
that were garbage collected.
60
self.pb = ui.ui_factory.progress_bar()
60
self.pb = ui.ui_factory.nested_progress_bar()
67
"""Helper function for performing reconciliation."""
61
68
self.repo = self.bzrdir.find_repository()
62
69
self.pb.note('Reconciling repository %s',
63
70
self.repo.bzrdir.root_transport.base)
86
93
garbage_inventories: The number of inventory objects without revisions
87
94
that were garbage collected.
89
self.pb = ui.ui_factory.progress_bar()
90
96
self.repo.lock_write()
92
self._reweave_inventory()
98
self.pb = ui.ui_factory.nested_progress_bar()
100
self._reweave_inventory()
94
104
self.repo.unlock()
96
106
def _reweave_inventory(self):
97
107
"""Regenerate the inventory weave for the repository from scratch."""
108
# local because its really a wart we want to hide
109
from bzrlib.weave import WeaveFile, Weave
110
transaction = self.repo.get_transaction()
98
111
self.pb.update('Reading inventory data.')
99
112
self.inventory = self.repo.get_inventory_weave()
100
113
# the total set of revisions to process
101
self.pending = set([file_id for file_id in self.repo.revision_store])
114
self.pending = set([rev_id for rev_id in self.repo._revision_store.all_revision_ids(transaction)])
103
116
# mapping from revision_id to parents
104
117
self._rev_graph = {}
109
122
for rev_id in self.pending:
110
123
# put a revision into the graph.
111
124
self._graph_revision(rev_id)
112
# we gc unreferenced inventories too
113
self.garbage_inventories = len(self.inventory.names()) \
114
- len(self._rev_graph)
125
self._check_garbage_inventories()
116
126
if not self.inconsistent_parents and not self.garbage_inventories:
117
127
self.pb.note('Inventory ok.')
119
129
self.pb.update('Backing up inventory...', 0, 0)
120
self.repo.control_weaves.put_weave('inventory.backup',
122
self.repo.get_transaction())
130
self.repo.control_weaves.copy(self.inventory, 'inventory.backup', self.repo.get_transaction())
123
131
self.pb.note('Backup Inventory created.')
124
132
# asking for '' should never return a non-empty weave
125
new_inventory = self.repo.control_weaves.get_weave_or_empty('',
133
new_inventory = self.repo.control_weaves.get_empty('inventory.new',
126
134
self.repo.get_transaction())
128
136
# we have topological order of revisions and non ghost parents ready.
135
143
# this entry has all the non ghost parents in the inventory
137
145
self._reweave_step('adding inventories')
138
new_inventory.add(rev_id, parents, self.inventory.get(rev_id))
146
# ugly but needed, weaves are just way tooooo slow else.
147
if isinstance(new_inventory, WeaveFile):
148
Weave.add_lines(new_inventory, rev_id, parents, self.inventory.get_lines(rev_id))
150
new_inventory.add_lines(rev_id, parents, self.inventory.get_lines(rev_id))
152
if isinstance(new_inventory, WeaveFile):
153
new_inventory._save()
140
154
# if this worked, the set of new_inventory.names should equal
142
assert set(new_inventory.names()) == self.pending
156
assert set(new_inventory.versions()) == self.pending
143
157
self.pb.update('Writing weave')
144
self.repo.control_weaves.put_weave('inventory',
146
self.repo.get_transaction())
158
self.repo.control_weaves.copy(new_inventory, 'inventory', self.repo.get_transaction())
159
self.repo.control_weaves.delete('inventory.new', self.repo.get_transaction())
147
160
self.inventory = None
148
161
self.pb.note('Inventory regenerated.')
167
180
mutter('found ghost %s', parent)
168
181
self._rev_graph[rev_id] = parents
169
if set(self.inventory.parent_names(rev_id)) != set(parents):
182
if set(self.inventory.get_parents(rev_id)) != set(parents):
170
183
self.inconsistent_parents += 1
184
mutter('Inconsistent inventory parents: id {%s} '
185
'inventory claims %r, '
186
'available parents are %r, '
187
'unavailable parents are %r',
189
set(self.inventory.get_parents(rev_id)),
191
set(rev.parent_ids).difference(set(parents)))
193
def _check_garbage_inventories(self):
194
"""Check for garbage inventories which we cannot trust
196
We cant trust them because their pre-requisite file data may not
197
be present - all we know is that their revision was not installed.
199
inventories = set(self.inventory.versions())
200
revisions = set(self._rev_graph.keys())
201
garbage = inventories.difference(revisions)
202
self.garbage_inventories = len(garbage)
203
for revision_id in garbage:
204
mutter('Garbage inventory {%s} found.', revision_id)
172
206
def _parent_is_available(self, parent):
173
207
"""True if parent is a fully available revision