~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/knitrepo.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-09-11 06:10:59 UTC
  • mfrom: (3702.1.1 trivial)
  • Revision ID: pqm@pqm.ubuntu.com-20080911061059-svzqfejar17ui4zw
(mbp) KnitVersionedFiles repr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from bzrlib.lazy_import import lazy_import
18
18
lazy_import(globals(), """
19
 
import itertools
20
 
 
 
19
from bzrlib import (
 
20
    debug,
 
21
    )
 
22
from bzrlib.store import revision
 
23
from bzrlib.store.revision.knit import KnitRevisionStore
 
24
""")
21
25
from bzrlib import (
22
26
    bzrdir,
23
27
    errors,
24
 
    knit as _mod_knit,
 
28
    knit,
25
29
    lockable_files,
26
30
    lockdir,
27
31
    osutils,
28
 
    revision as _mod_revision,
29
 
    trace,
 
32
    symbol_versioning,
30
33
    transactions,
31
 
    versionedfile,
32
34
    xml5,
33
35
    xml6,
34
36
    xml7,
35
37
    )
36
 
""")
37
38
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
39
from bzrlib.knit import KnitVersionedFiles, _KndxIndex, _KnitKeyAccess
38
40
from bzrlib.repository import (
39
 
    InterRepository,
40
 
    IsInWriteGroupError,
 
41
    CommitBuilder,
 
42
    MetaDirRepository,
 
43
    MetaDirRepositoryFormat,
41
44
    RepositoryFormat,
42
 
    )
43
 
from bzrlib.vf_repository import (
44
 
    InterSameDataRepository,
45
 
    MetaDirVersionedFileRepository,
46
 
    MetaDirVersionedFileRepositoryFormat,
47
 
    VersionedFileCommitBuilder,
48
 
    VersionedFileRootCommitBuilder,
49
 
    )
50
 
from bzrlib import symbol_versioning
 
45
    RootCommitBuilder,
 
46
    )
 
47
import bzrlib.revision as _mod_revision
 
48
from bzrlib.store.versioned import VersionedFileStore
 
49
from bzrlib.trace import mutter, mutter_callsite
 
50
from bzrlib.util import bencode
 
51
from bzrlib.versionedfile import ConstantMapper, HashEscapedPrefixMapper
51
52
 
52
53
 
53
54
class _KnitParentsProvider(object):
58
59
    def __repr__(self):
59
60
        return 'KnitParentsProvider(%r)' % self._knit
60
61
 
 
62
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
63
    def get_parents(self, revision_ids):
 
64
        """See graph._StackedParentsProvider.get_parents"""
 
65
        parent_map = self.get_parent_map(revision_ids)
 
66
        return [parent_map.get(r, None) for r in revision_ids]
 
67
 
61
68
    def get_parent_map(self, keys):
62
 
        """See graph.StackedParentsProvider.get_parent_map"""
 
69
        """See graph._StackedParentsProvider.get_parent_map"""
63
70
        parent_map = {}
64
71
        for revision_id in keys:
65
72
            if revision_id is None:
90
97
        return 'KnitsParentsProvider(%r)' % self._knit
91
98
 
92
99
    def get_parent_map(self, keys):
93
 
        """See graph.StackedParentsProvider.get_parent_map"""
 
100
        """See graph._StackedParentsProvider.get_parent_map"""
94
101
        parent_map = self._knit.get_parent_map(
95
102
            [self._prefix + (key,) for key in keys])
96
103
        result = {}
107
114
        return result
108
115
 
109
116
 
110
 
class KnitRepository(MetaDirVersionedFileRepository):
 
117
class KnitRepository(MetaDirRepository):
111
118
    """Knit format repository."""
112
119
 
113
120
    # These attributes are inherited from the Repository base class. Setting
119
126
 
120
127
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
121
128
        _serializer):
122
 
        super(KnitRepository, self).__init__(_format, a_bzrdir, control_files)
 
129
        MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
123
130
        self._commit_builder_class = _commit_builder_class
124
131
        self._serializer = _serializer
125
132
        self._reconcile_fixes_text_parents = True
 
133
        self._fetch_uses_deltas = True
 
134
        self._fetch_order = 'topological'
126
135
 
127
136
    @needs_read_lock
128
137
    def _all_revision_ids(self):
181
190
        result.get_parent_map([('A',)])
182
191
        return result
183
192
 
 
193
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
194
        """Find file_id(s) which are involved in the changes between revisions.
 
195
 
 
196
        This determines the set of revisions which are involved, and then
 
197
        finds all file ids affected by those revisions.
 
198
        """
 
199
        vf = self._get_revision_vf()
 
200
        from_set = set(vf.get_ancestry(from_revid))
 
201
        to_set = set(vf.get_ancestry(to_revid))
 
202
        changed = to_set.difference(from_set)
 
203
        return self._fileid_involved_by_set(changed)
 
204
 
 
205
    def fileid_involved(self, last_revid=None):
 
206
        """Find all file_ids modified in the ancestry of last_revid.
 
207
 
 
208
        :param last_revid: If None, last_revision() will be used.
 
209
        """
 
210
        if not last_revid:
 
211
            changed = set(self.all_revision_ids())
 
212
        else:
 
213
            changed = set(self.get_ancestry(last_revid))
 
214
        if None in changed:
 
215
            changed.remove(None)
 
216
        return self._fileid_involved_by_set(changed)
 
217
 
184
218
    @needs_read_lock
185
219
    def get_revision(self, revision_id):
186
220
        """Return the Revision object for a named revision"""
187
221
        revision_id = osutils.safe_revision_id(revision_id)
188
222
        return self.get_revision_reconcile(revision_id)
189
223
 
190
 
    def _refresh_data(self):
191
 
        if not self.is_locked():
192
 
            return
193
 
        if self.is_in_write_group():
194
 
            raise IsInWriteGroupError(self)
195
 
        # Create a new transaction to force all knits to see the scope change.
196
 
        # This is safe because we're outside a write group.
197
 
        self.control_files._finish_transaction()
198
 
        if self.is_write_locked():
199
 
            self.control_files._set_write_transaction()
200
 
        else:
201
 
            self.control_files._set_read_transaction()
202
 
 
203
224
    @needs_write_lock
204
225
    def reconcile(self, other=None, thorough=False):
205
226
        """Reconcile this repository."""
207
228
        reconciler = KnitReconciler(self, thorough=thorough)
208
229
        reconciler.reconcile()
209
230
        return reconciler
210
 
 
 
231
    
211
232
    def _make_parents_provider(self):
212
233
        return _KnitsParentsProvider(self.revisions)
213
234
 
214
 
 
215
 
class RepositoryFormatKnit(MetaDirVersionedFileRepositoryFormat):
216
 
    """Bzr repository knit format (generalized).
 
235
    def _find_inconsistent_revision_parents(self):
 
236
        """Find revisions with different parent lists in the revision object
 
237
        and in the index graph.
 
238
 
 
239
        :returns: an iterator yielding tuples of (revison-id, parents-in-index,
 
240
            parents-in-revision).
 
241
        """
 
242
        if not self.is_locked():
 
243
            raise AssertionError()
 
244
        vf = self.revisions
 
245
        for index_version in vf.keys():
 
246
            parent_map = vf.get_parent_map([index_version])
 
247
            parents_according_to_index = tuple(parent[-1] for parent in
 
248
                parent_map[index_version])
 
249
            revision = self.get_revision(index_version[-1])
 
250
            parents_according_to_revision = tuple(revision.parent_ids)
 
251
            if parents_according_to_index != parents_according_to_revision:
 
252
                yield (index_version[-1], parents_according_to_index,
 
253
                    parents_according_to_revision)
 
254
 
 
255
    def _check_for_inconsistent_revision_parents(self):
 
256
        inconsistencies = list(self._find_inconsistent_revision_parents())
 
257
        if inconsistencies:
 
258
            raise errors.BzrCheckError(
 
259
                "Revision knit has inconsistent parents.")
 
260
 
 
261
    def revision_graph_can_have_wrong_parents(self):
 
262
        # The revision.kndx could potentially claim a revision has a different
 
263
        # parent to the revision text.
 
264
        return True
 
265
 
 
266
 
 
267
class RepositoryFormatKnit(MetaDirRepositoryFormat):
 
268
    """Bzr repository knit format (generalized). 
217
269
 
218
270
    This repository format has:
219
271
     - knits for file texts and inventory
235
287
    _commit_builder_class = None
236
288
    # Set this attribute in derived clases to control the _serializer that the
237
289
    # repository objects will have passed to their constructor.
238
 
    @property
239
 
    def _serializer(self):
240
 
        return xml5.serializer_v5
 
290
    _serializer = xml5.serializer_v5
241
291
    # Knit based repositories handle ghosts reasonably well.
242
292
    supports_ghosts = True
243
293
    # External lookups are not supported in this format.
244
294
    supports_external_lookups = False
245
 
    # No CHK support.
246
 
    supports_chks = False
247
 
    _fetch_order = 'topological'
248
 
    _fetch_uses_deltas = True
249
 
    fast_deltas = False
250
 
    supports_funky_characters = True
251
 
    # The revision.kndx could potentially claim a revision has a different
252
 
    # parent to the revision text.
253
 
    revision_graph_can_have_wrong_parents = True
254
295
 
255
296
    def _get_inventories(self, repo_transport, repo, name='inventory'):
256
 
        mapper = versionedfile.ConstantMapper(name)
257
 
        index = _mod_knit._KndxIndex(repo_transport, mapper,
258
 
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
259
 
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
260
 
        return _mod_knit.KnitVersionedFiles(index, access, annotated=False)
 
297
        mapper = ConstantMapper(name)
 
298
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
 
299
            repo.is_write_locked, repo.is_locked)
 
300
        access = _KnitKeyAccess(repo_transport, mapper)
 
301
        return KnitVersionedFiles(index, access, annotated=False)
261
302
 
262
303
    def _get_revisions(self, repo_transport, repo):
263
 
        mapper = versionedfile.ConstantMapper('revisions')
264
 
        index = _mod_knit._KndxIndex(repo_transport, mapper,
265
 
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
266
 
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
267
 
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
 
304
        mapper = ConstantMapper('revisions')
 
305
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
 
306
            repo.is_write_locked, repo.is_locked)
 
307
        access = _KnitKeyAccess(repo_transport, mapper)
 
308
        return KnitVersionedFiles(index, access, max_delta_chain=0,
268
309
            annotated=False)
269
310
 
270
311
    def _get_signatures(self, repo_transport, repo):
271
 
        mapper = versionedfile.ConstantMapper('signatures')
272
 
        index = _mod_knit._KndxIndex(repo_transport, mapper,
273
 
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
274
 
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
275
 
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
 
312
        mapper = ConstantMapper('signatures')
 
313
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
 
314
            repo.is_write_locked, repo.is_locked)
 
315
        access = _KnitKeyAccess(repo_transport, mapper)
 
316
        return KnitVersionedFiles(index, access, max_delta_chain=0,
276
317
            annotated=False)
277
318
 
278
319
    def _get_texts(self, repo_transport, repo):
279
 
        mapper = versionedfile.HashEscapedPrefixMapper()
 
320
        mapper = HashEscapedPrefixMapper()
280
321
        base_transport = repo_transport.clone('knits')
281
 
        index = _mod_knit._KndxIndex(base_transport, mapper,
282
 
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
283
 
        access = _mod_knit._KnitKeyAccess(base_transport, mapper)
284
 
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=200,
 
322
        index = _KndxIndex(base_transport, mapper, repo.get_transaction,
 
323
            repo.is_write_locked, repo.is_locked)
 
324
        access = _KnitKeyAccess(base_transport, mapper)
 
325
        return KnitVersionedFiles(index, access, max_delta_chain=200,
285
326
            annotated=True)
286
327
 
287
328
    def initialize(self, a_bzrdir, shared=False):
292
333
        :param shared: If true the repository will be initialized as a shared
293
334
                       repository.
294
335
        """
295
 
        trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
 
336
        mutter('creating repository in %s.', a_bzrdir.transport.base)
296
337
        dirs = ['knits']
297
338
        files = []
298
339
        utf8_files = [('format', self.get_format_string())]
299
 
 
 
340
        
300
341
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
301
342
        repo_transport = a_bzrdir.get_repository_transport(None)
302
343
        control_files = lockable_files.LockableFiles(repo_transport,
310
351
        result.revisions.get_parent_map([('A',)])
311
352
        result.signatures.get_parent_map([('A',)])
312
353
        result.unlock()
313
 
        self._run_post_repo_init_hooks(result, a_bzrdir, shared)
314
354
        return result
315
355
 
316
356
    def open(self, a_bzrdir, _found=False, _override_transport=None):
317
357
        """See RepositoryFormat.open().
318
 
 
 
358
        
319
359
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
320
360
                                    repository at a slightly different url
321
361
                                    than normal. I.e. during 'upgrade'.
337
377
        repo.signatures = self._get_signatures(repo_transport, repo)
338
378
        repo.inventories = self._get_inventories(repo_transport, repo)
339
379
        repo.texts = self._get_texts(repo_transport, repo)
340
 
        repo.chk_bytes = None
341
380
        repo._transport = repo_transport
342
381
        return repo
343
382
 
359
398
    """
360
399
 
361
400
    repository_class = KnitRepository
362
 
    _commit_builder_class = VersionedFileCommitBuilder
363
 
    @property
364
 
    def _serializer(self):
365
 
        return xml5.serializer_v5
 
401
    _commit_builder_class = CommitBuilder
 
402
    _serializer = xml5.serializer_v5
366
403
 
367
404
    def __ne__(self, other):
368
405
        return self.__class__ is not other.__class__
375
412
        """See RepositoryFormat.get_format_description()."""
376
413
        return "Knit repository format 1"
377
414
 
 
415
    def check_conversion_target(self, target_format):
 
416
        pass
 
417
 
378
418
 
379
419
class RepositoryFormatKnit3(RepositoryFormatKnit):
380
420
    """Bzr repository knit format 3.
393
433
    """
394
434
 
395
435
    repository_class = KnitRepository
396
 
    _commit_builder_class = VersionedFileRootCommitBuilder
 
436
    _commit_builder_class = RootCommitBuilder
397
437
    rich_root_data = True
398
 
    experimental = True
399
438
    supports_tree_reference = True
400
 
    @property
401
 
    def _serializer(self):
402
 
        return xml7.serializer_v7
 
439
    _serializer = xml7.serializer_v7
403
440
 
404
441
    def _get_matching_bzrdir(self):
405
442
        return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
409
446
 
410
447
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
411
448
 
 
449
    def check_conversion_target(self, target_format):
 
450
        if not target_format.rich_root_data:
 
451
            raise errors.BadConversionTarget(
 
452
                'Does not support rich root data.', target_format)
 
453
        if not getattr(target_format, 'supports_tree_reference', False):
 
454
            raise errors.BadConversionTarget(
 
455
                'Does not support nested trees', target_format)
 
456
            
412
457
    def get_format_string(self):
413
458
        """See RepositoryFormat.get_format_string()."""
414
459
        return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
435
480
    """
436
481
 
437
482
    repository_class = KnitRepository
438
 
    _commit_builder_class = VersionedFileRootCommitBuilder
 
483
    _commit_builder_class = RootCommitBuilder
439
484
    rich_root_data = True
440
485
    supports_tree_reference = False
441
 
    @property
442
 
    def _serializer(self):
443
 
        return xml6.serializer_v6
 
486
    _serializer = xml6.serializer_v6
444
487
 
445
488
    def _get_matching_bzrdir(self):
446
489
        return bzrdir.format_registry.make_bzrdir('rich-root')
450
493
 
451
494
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
452
495
 
 
496
    def check_conversion_target(self, target_format):
 
497
        if not target_format.rich_root_data:
 
498
            raise errors.BadConversionTarget(
 
499
                'Does not support rich root data.', target_format)
 
500
 
453
501
    def get_format_string(self):
454
502
        """See RepositoryFormat.get_format_string()."""
455
503
        return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
457
505
    def get_format_description(self):
458
506
        """See RepositoryFormat.get_format_description()."""
459
507
        return "Knit repository format 4"
460
 
 
461
 
 
462
 
class InterKnitRepo(InterSameDataRepository):
463
 
    """Optimised code paths between Knit based repositories."""
464
 
 
465
 
    @classmethod
466
 
    def _get_repo_format_to_test(self):
467
 
        return RepositoryFormatKnit1()
468
 
 
469
 
    @staticmethod
470
 
    def is_compatible(source, target):
471
 
        """Be compatible with known Knit formats.
472
 
 
473
 
        We don't test for the stores being of specific types because that
474
 
        could lead to confusing results, and there is no need to be
475
 
        overly general.
476
 
        """
477
 
        try:
478
 
            are_knits = (isinstance(source._format, RepositoryFormatKnit) and
479
 
                isinstance(target._format, RepositoryFormatKnit))
480
 
        except AttributeError:
481
 
            return False
482
 
        return are_knits and InterRepository._same_model(source, target)
483
 
 
484
 
    @needs_read_lock
485
 
    def search_missing_revision_ids(self,
486
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
487
 
            find_ghosts=True, revision_ids=None, if_present_ids=None,
488
 
            limit=None):
489
 
        """See InterRepository.search_missing_revision_ids()."""
490
 
        if symbol_versioning.deprecated_passed(revision_id):
491
 
            symbol_versioning.warn(
492
 
                'search_missing_revision_ids(revision_id=...) was '
493
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
494
 
                DeprecationWarning, stacklevel=2)
495
 
            if revision_ids is not None:
496
 
                raise AssertionError(
497
 
                    'revision_ids is mutually exclusive with revision_id')
498
 
            if revision_id is not None:
499
 
                revision_ids = [revision_id]
500
 
        del revision_id
501
 
        source_ids_set = self._present_source_revisions_for(
502
 
            revision_ids, if_present_ids)
503
 
        # source_ids is the worst possible case we may need to pull.
504
 
        # now we want to filter source_ids against what we actually
505
 
        # have in target, but don't try to check for existence where we know
506
 
        # we do not have a revision as that would be pointless.
507
 
        target_ids = set(self.target.all_revision_ids())
508
 
        possibly_present_revisions = target_ids.intersection(source_ids_set)
509
 
        actually_present_revisions = set(
510
 
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
511
 
        required_revisions = source_ids_set.difference(actually_present_revisions)
512
 
        if revision_ids is not None:
513
 
            # we used get_ancestry to determine source_ids then we are assured all
514
 
            # revisions referenced are present as they are installed in topological order.
515
 
            # and the tip revision was validated by get_ancestry.
516
 
            result_set = required_revisions
517
 
        else:
518
 
            # if we just grabbed the possibly available ids, then
519
 
            # we only have an estimate of whats available and need to validate
520
 
            # that against the revision records.
521
 
            result_set = set(
522
 
                self.source._eliminate_revisions_not_present(required_revisions))
523
 
        if limit is not None:
524
 
            topo_ordered = self.source.get_graph().iter_topo_order(result_set)
525
 
            result_set = set(itertools.islice(topo_ordered, limit))
526
 
        return self.source.revision_ids_to_search_result(result_set)
527
 
 
528
 
 
529
 
InterRepository.register_optimiser(InterKnitRepo)