~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/check.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
so that when the dependent object is checked, matches can be pulled out and
40
40
evaluated in-line rather than re-reading the same data many times.
41
41
check_refs are tuples (kind, value). Currently defined kinds are:
 
42
 
42
43
* 'trees', where value is a revid and the looked up objects are revision trees.
43
44
* 'lefthand-distance', where value is a revid and the looked up objects are the
44
45
  distance along the lefthand path to NULL for that revid.
46
47
  indicating that the revision was found/not found.
47
48
"""
48
49
 
49
 
from bzrlib import errors
 
50
from __future__ import absolute_import
 
51
 
 
52
from bzrlib import (
 
53
    errors,
 
54
    ui,
 
55
    )
50
56
from bzrlib.branch import Branch
51
 
from bzrlib.bzrdir import BzrDir
 
57
from bzrlib.controldir import ControlDir
52
58
from bzrlib.revision import NULL_REVISION
53
 
from bzrlib.symbol_versioning import deprecated_function, deprecated_in
54
59
from bzrlib.trace import note
55
 
import bzrlib.ui
56
60
from bzrlib.workingtree import WorkingTree
 
61
from bzrlib.i18n import gettext
57
62
 
58
63
class Check(object):
59
64
    """Check a repository"""
60
65
 
 
66
    def __init__(self, repository, check_repo=True):
 
67
        self.repository = repository
 
68
 
 
69
    def report_results(self, verbose):
 
70
        raise NotImplementedError(self.report_results)
 
71
 
 
72
 
 
73
class VersionedFileCheck(Check):
 
74
    """Check a versioned file repository"""
 
75
 
61
76
    # The Check object interacts with InventoryEntry.check, etc.
62
77
 
63
78
    def __init__(self, repository, check_repo=True):
88
103
        if callback_refs is None:
89
104
            callback_refs = {}
90
105
        self.repository.lock_read()
91
 
        self.progress = bzrlib.ui.ui_factory.nested_progress_bar()
 
106
        self.progress = ui.ui_factory.nested_progress_bar()
92
107
        try:
93
 
            self.progress.update('check', 0, 4)
 
108
            self.progress.update(gettext('check'), 0, 4)
94
109
            if self.check_repo:
95
 
                self.progress.update('checking revisions', 0)
 
110
                self.progress.update(gettext('checking revisions'), 0)
96
111
                self.check_revisions()
97
 
                self.progress.update('checking commit contents', 1)
 
112
                self.progress.update(gettext('checking commit contents'), 1)
98
113
                self.repository._check_inventories(self)
99
 
                self.progress.update('checking file graphs', 2)
 
114
                self.progress.update(gettext('checking file graphs'), 2)
100
115
                # check_weaves is done after the revision scan so that
101
116
                # revision index is known to be valid.
102
117
                self.check_weaves()
103
 
            self.progress.update('checking branches and trees', 3)
 
118
            self.progress.update(gettext('checking branches and trees'), 3)
104
119
            if callback_refs:
105
120
                repo = self.repository
106
121
                # calculate all refs, and callback the objects requesting them.
170
185
        # - we can fill out existence flags at this point
171
186
        # - we can read the revision inventory sha at this point
172
187
        # - we can check properties and serialisers etc.
173
 
        if not self.repository.revision_graph_can_have_wrong_parents():
 
188
        if not self.repository._format.revision_graph_can_have_wrong_parents:
174
189
            # The check against the index isn't needed.
175
190
            self.revs_with_bad_parents_in_index = None
176
191
            for thing in revision_iterator:
187
202
            result.report_results(verbose)
188
203
 
189
204
    def _report_repo_results(self, verbose):
190
 
        note('checked repository %s format %s',
 
205
        note(gettext('checked repository {0} format {1}').format(
191
206
            self.repository.user_url,
192
 
            self.repository._format)
193
 
        note('%6d revisions', self.checked_rev_cnt)
194
 
        note('%6d file-ids', len(self.checked_weaves))
 
207
            self.repository._format))
 
208
        note(gettext('%6d revisions'), self.checked_rev_cnt)
 
209
        note(gettext('%6d file-ids'), len(self.checked_weaves))
195
210
        if verbose:
196
 
            note('%6d unreferenced text versions',
 
211
            note(gettext('%6d unreferenced text versions'),
197
212
                len(self.unreferenced_versions))
198
213
        if verbose and len(self.unreferenced_versions):
199
214
                for file_id, revision_id in self.unreferenced_versions:
200
 
                    note('unreferenced version: {%s} in %s', revision_id,
201
 
                        file_id)
 
215
                    note(gettext('unreferenced version: {{{0}}} in {1}').format(revision_id,
 
216
                        file_id))
202
217
        if self.missing_inventory_sha_cnt:
203
 
            note('%6d revisions are missing inventory_sha1',
 
218
            note(gettext('%6d revisions are missing inventory_sha1'),
204
219
                 self.missing_inventory_sha_cnt)
205
220
        if self.missing_revision_cnt:
206
 
            note('%6d revisions are mentioned but not present',
 
221
            note(gettext('%6d revisions are mentioned but not present'),
207
222
                 self.missing_revision_cnt)
208
223
        if len(self.ghosts):
209
 
            note('%6d ghost revisions', len(self.ghosts))
 
224
            note(gettext('%6d ghost revisions'), len(self.ghosts))
210
225
            if verbose:
211
226
                for ghost in self.ghosts:
212
227
                    note('      %s', ghost)
213
228
        if len(self.missing_parent_links):
214
 
            note('%6d revisions missing parents in ancestry',
 
229
            note(gettext('%6d revisions missing parents in ancestry'),
215
230
                 len(self.missing_parent_links))
216
231
            if verbose:
217
232
                for link, linkers in self.missing_parent_links.items():
218
 
                    note('      %s should be in the ancestry for:', link)
 
233
                    note(gettext('      %s should be in the ancestry for:'), link)
219
234
                    for linker in linkers:
220
235
                        note('       * %s', linker)
221
236
        if len(self.inconsistent_parents):
222
 
            note('%6d inconsistent parents', len(self.inconsistent_parents))
 
237
            note(gettext('%6d inconsistent parents'), len(self.inconsistent_parents))
223
238
            if verbose:
224
239
                for info in self.inconsistent_parents:
225
240
                    revision_id, file_id, found_parents, correct_parents = info
226
 
                    note('      * %s version %s has parents %r '
227
 
                         'but should have %r'
228
 
                         % (file_id, revision_id, found_parents,
 
241
                    note(gettext('      * {0} version {1} has parents {2!r} '
 
242
                         'but should have {3!r}').format(
 
243
                         file_id, revision_id, found_parents,
229
244
                             correct_parents))
230
245
        if self.revs_with_bad_parents_in_index:
231
 
            note('%6d revisions have incorrect parents in the revision index',
 
246
            note(gettext(
 
247
                 '%6d revisions have incorrect parents in the revision index'),
232
248
                 len(self.revs_with_bad_parents_in_index))
233
249
            if verbose:
234
250
                for item in self.revs_with_bad_parents_in_index:
235
251
                    revision_id, index_parents, actual_parents = item
236
 
                    note(
237
 
                        '       %s has wrong parents in index: '
238
 
                        '%r should be %r',
239
 
                        revision_id, index_parents, actual_parents)
 
252
                    note(gettext(
 
253
                        '       {0} has wrong parents in index: '
 
254
                        '{1!r} should be {2!r}').format(
 
255
                        revision_id, index_parents, actual_parents))
240
256
        for item in self._report_items:
241
257
            note(item)
242
258
 
247
263
        :param rev: A revision or None to indicate a missing revision.
248
264
        """
249
265
        if rev.revision_id != rev_id:
250
 
            self._report_items.append(
251
 
                'Mismatched internal revid {%s} and index revid {%s}' % (
 
266
            self._report_items.append(gettext(
 
267
                'Mismatched internal revid {{{0}}} and index revid {{{1}}}').format(
252
268
                rev.revision_id, rev_id))
253
269
            rev_id = rev.revision_id
254
270
        # Check this revision tree etc, and count as seen when we encounter a
277
293
        existing = self.pending_keys.get(key)
278
294
        if existing:
279
295
            if sha1 != existing[1]:
280
 
                self._report_items.append('Multiple expected sha1s for %s. {%s}'
281
 
                    ' expects {%s}, {%s} expects {%s}', (
 
296
                self._report_items.append(gettext('Multiple expected sha1s for {0}. {{{1}}}'
 
297
                    ' expects {{{2}}}, {{{3}}} expects {{{4}}}').format(
282
298
                    key, referer, sha1, existing[1], existing[0]))
283
299
        else:
284
300
            self.pending_keys[key] = (kind, sha1, referer)
287
303
        """Check all the weaves we can get our hands on.
288
304
        """
289
305
        weave_ids = []
290
 
        storebar = bzrlib.ui.ui_factory.nested_progress_bar()
 
306
        storebar = ui.ui_factory.nested_progress_bar()
291
307
        try:
292
308
            self._check_weaves(storebar)
293
309
        finally:
328
344
            self.text_key_references[key] = True
329
345
 
330
346
 
331
 
@deprecated_function(deprecated_in((1,6,0)))
332
 
def check(branch, verbose):
333
 
    """Run consistency checks on a branch.
334
 
 
335
 
    Results are reported through logging.
336
 
 
337
 
    Deprecated in 1.6.  Please use check_dwim instead.
338
 
 
339
 
    :raise BzrCheckError: if there's a consistency error.
340
 
    """
341
 
    check_branch(branch, verbose)
342
 
 
343
 
 
344
 
@deprecated_function(deprecated_in((1,16,0)))
345
 
def check_branch(branch, verbose):
346
 
    """Run consistency checks on a branch.
347
 
 
348
 
    Results are reported through logging.
349
 
 
350
 
    :raise BzrCheckError: if there's a consistency error.
351
 
    """
352
 
    branch.lock_read()
353
 
    try:
354
 
        needed_refs = {}
355
 
        for ref in branch._get_check_refs():
356
 
            needed_refs.setdefault(ref, []).append(branch)
357
 
        result = branch.repository.check([branch.last_revision()], needed_refs)
358
 
        branch_result = result.other_results[0]
359
 
    finally:
360
 
        branch.unlock()
361
 
    branch_result.report_results(verbose)
362
 
 
363
 
 
364
347
def scan_branch(branch, needed_refs, to_unlock):
365
348
    """Scan a branch for refs.
366
349
 
368
351
    :param needed_refs: Refs we are accumulating.
369
352
    :param to_unlock: The unlock list accumulating.
370
353
    """
371
 
    note("Checking branch at '%s'." % (branch.base,))
 
354
    note(gettext("Checking branch at '%s'.") % (branch.base,))
372
355
    branch.lock_read()
373
356
    to_unlock.append(branch)
374
357
    branch_refs = branch._get_check_refs()
388
371
    """
389
372
    if base_tree is not None and tree.basedir == base_tree.basedir:
390
373
        return
391
 
    note("Checking working tree at '%s'." % (tree.basedir,))
 
374
    note(gettext("Checking working tree at '%s'.") % (tree.basedir,))
392
375
    tree.lock_read()
393
376
    to_unlock.append(tree)
394
377
    tree_refs = tree._get_check_refs()
405
388
    """
406
389
    try:
407
390
        base_tree, branch, repo, relpath = \
408
 
                        BzrDir.open_containing_tree_branch_or_repository(path)
 
391
                        ControlDir.open_containing_tree_branch_or_repository(path)
409
392
    except errors.NotBranchError:
410
393
        base_tree = branch = repo = None
411
394
 
441
424
                    if do_branch:
442
425
                        scan_branch(branch, needed_refs, to_unlock)
443
426
            if do_branch and not branches:
444
 
                note("No branch found at specified location.")
 
427
                note(gettext("No branch found at specified location."))
445
428
            if do_tree and base_tree is None and not saw_tree:
446
 
                note("No working tree found at specified location.")
 
429
                note(gettext("No working tree found at specified location."))
447
430
            if do_repo or do_branch or do_tree:
448
431
                if do_repo:
449
 
                    note("Checking repository at '%s'."
 
432
                    note(gettext("Checking repository at '%s'.")
450
433
                         % (repo.user_url,))
451
434
                result = repo.check(None, callback_refs=needed_refs,
452
435
                    check_repo=do_repo)
453
436
                result.report_results(verbose)
454
437
        else:
455
438
            if do_tree:
456
 
                note("No working tree found at specified location.")
 
439
                note(gettext("No working tree found at specified location."))
457
440
            if do_branch:
458
 
                note("No branch found at specified location.")
 
441
                note(gettext("No branch found at specified location."))
459
442
            if do_repo:
460
 
                note("No repository found at specified location.")
 
443
                note(gettext("No repository found at specified location."))
461
444
    finally:
462
445
        for thing in to_unlock:
463
446
            thing.unlock()