/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/knitrepo.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
 
from ..lazy_import import lazy_import
 
17
from bzrlib.lazy_import import lazy_import
20
18
lazy_import(globals(), """
21
 
import itertools
22
 
 
23
 
from breezy import (
24
 
    controldir,
 
19
from bzrlib import (
 
20
    bzrdir,
25
21
    errors,
 
22
    knit as _mod_knit,
26
23
    lockable_files,
27
24
    lockdir,
28
25
    osutils,
29
26
    revision as _mod_revision,
30
27
    trace,
31
28
    transactions,
32
 
    )
33
 
from breezy.bzr import (
34
 
    knit as _mod_knit,
35
29
    versionedfile,
36
30
    xml5,
37
31
    xml6,
38
32
    xml7,
39
33
    )
40
34
""")
41
 
from ..repository import (
42
 
    InterRepository,
43
 
    IsInWriteGroupError,
44
 
    )
45
 
from ..bzr.repository import (
46
 
    RepositoryFormatMetaDir,
47
 
    )
48
 
from ..bzr.vf_repository import (
49
 
    InterSameDataRepository,
50
 
    MetaDirVersionedFileRepository,
51
 
    MetaDirVersionedFileRepositoryFormat,
52
 
    VersionedFileCommitBuilder,
 
35
from bzrlib import (
 
36
    symbol_versioning,
 
37
    )
 
38
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
39
from bzrlib.repository import (
 
40
    CommitBuilder,
 
41
    MetaDirRepository,
 
42
    MetaDirRepositoryFormat,
 
43
    RepositoryFormat,
 
44
    RootCommitBuilder,
53
45
    )
54
46
 
55
47
 
110
102
        return result
111
103
 
112
104
 
113
 
class KnitRepository(MetaDirVersionedFileRepository):
 
105
class KnitRepository(MetaDirRepository):
114
106
    """Knit format repository."""
115
107
 
116
108
    # These attributes are inherited from the Repository base class. Setting
120
112
    _commit_builder_class = None
121
113
    _serializer = None
122
114
 
123
 
    def __init__(self, _format, a_controldir, control_files, _commit_builder_class,
124
 
                 _serializer):
125
 
        super(KnitRepository, self).__init__(
126
 
            _format, a_controldir, control_files)
 
115
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
 
116
        _serializer):
 
117
        MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
127
118
        self._commit_builder_class = _commit_builder_class
128
119
        self._serializer = _serializer
129
120
        self._reconcile_fixes_text_parents = True
130
121
 
 
122
    @needs_read_lock
131
123
    def _all_revision_ids(self):
132
124
        """See Repository.all_revision_ids()."""
133
 
        with self.lock_read():
134
 
            return [key[0] for key in self.revisions.keys()]
 
125
        return [key[0] for key in self.revisions.keys()]
135
126
 
136
127
    def _activate_new_inventory(self):
137
128
        """Put a replacement inventory.new into use as inventories."""
178
169
 
179
170
    def _temp_inventories(self):
180
171
        result = self._format._get_inventories(self._transport, self,
181
 
                                               'inventory.new')
 
172
            'inventory.new')
182
173
        # Reconciling when the output has no revisions would result in no
183
174
        # writes - but we want to ensure there is an inventory for
184
175
        # compatibility with older clients that don't lazy-load.
185
 
        result.get_parent_map([(b'A',)])
 
176
        result.get_parent_map([('A',)])
186
177
        return result
187
178
 
 
179
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
180
        """Find file_id(s) which are involved in the changes between revisions.
 
181
 
 
182
        This determines the set of revisions which are involved, and then
 
183
        finds all file ids affected by those revisions.
 
184
        """
 
185
        vf = self._get_revision_vf()
 
186
        from_set = set(vf.get_ancestry(from_revid))
 
187
        to_set = set(vf.get_ancestry(to_revid))
 
188
        changed = to_set.difference(from_set)
 
189
        return self._fileid_involved_by_set(changed)
 
190
 
 
191
    def fileid_involved(self, last_revid=None):
 
192
        """Find all file_ids modified in the ancestry of last_revid.
 
193
 
 
194
        :param last_revid: If None, last_revision() will be used.
 
195
        """
 
196
        if not last_revid:
 
197
            changed = set(self.all_revision_ids())
 
198
        else:
 
199
            changed = set(self.get_ancestry(last_revid))
 
200
        if None in changed:
 
201
            changed.remove(None)
 
202
        return self._fileid_involved_by_set(changed)
 
203
 
 
204
    @needs_read_lock
188
205
    def get_revision(self, revision_id):
189
206
        """Return the Revision object for a named revision"""
190
207
        revision_id = osutils.safe_revision_id(revision_id)
191
 
        with self.lock_read():
192
 
            return self.get_revision_reconcile(revision_id)
 
208
        return self.get_revision_reconcile(revision_id)
193
209
 
194
210
    def _refresh_data(self):
195
211
        if not self.is_locked():
196
212
            return
197
 
        if self.is_in_write_group():
198
 
            raise IsInWriteGroupError(self)
199
213
        # Create a new transaction to force all knits to see the scope change.
200
214
        # This is safe because we're outside a write group.
201
215
        self.control_files._finish_transaction()
204
218
        else:
205
219
            self.control_files._set_read_transaction()
206
220
 
 
221
    @needs_write_lock
207
222
    def reconcile(self, other=None, thorough=False):
208
223
        """Reconcile this repository."""
209
 
        from .reconcile import KnitReconciler
210
 
        with self.lock_write():
211
 
            reconciler = KnitReconciler(self, thorough=thorough)
212
 
            return reconciler.reconcile()
 
224
        from bzrlib.reconcile import KnitReconciler
 
225
        reconciler = KnitReconciler(self, thorough=thorough)
 
226
        reconciler.reconcile()
 
227
        return reconciler
213
228
 
214
229
    def _make_parents_provider(self):
215
230
        return _KnitsParentsProvider(self.revisions)
216
231
 
217
 
 
218
 
class RepositoryFormatKnit(MetaDirVersionedFileRepositoryFormat):
 
232
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
 
233
        """Find revisions with different parent lists in the revision object
 
234
        and in the index graph.
 
235
 
 
236
        :param revisions_iterator: None, or an iterator of (revid,
 
237
            Revision-or-None). This iterator controls the revisions checked.
 
238
        :returns: an iterator yielding tuples of (revison-id, parents-in-index,
 
239
            parents-in-revision).
 
240
        """
 
241
        if not self.is_locked():
 
242
            raise AssertionError()
 
243
        vf = self.revisions
 
244
        if revisions_iterator is None:
 
245
            revisions_iterator = self._iter_revisions(None)
 
246
        for revid, revision in revisions_iterator:
 
247
            if revision is None:
 
248
                pass
 
249
            parent_map = vf.get_parent_map([(revid,)])
 
250
            parents_according_to_index = tuple(parent[-1] for parent in
 
251
                parent_map[(revid,)])
 
252
            parents_according_to_revision = tuple(revision.parent_ids)
 
253
            if parents_according_to_index != parents_according_to_revision:
 
254
                yield (revid, parents_according_to_index,
 
255
                    parents_according_to_revision)
 
256
 
 
257
    def _check_for_inconsistent_revision_parents(self):
 
258
        inconsistencies = list(self._find_inconsistent_revision_parents())
 
259
        if inconsistencies:
 
260
            raise errors.BzrCheckError(
 
261
                "Revision knit has inconsistent parents.")
 
262
 
 
263
    def revision_graph_can_have_wrong_parents(self):
 
264
        # The revision.kndx could potentially claim a revision has a different
 
265
        # parent to the revision text.
 
266
        return True
 
267
 
 
268
 
 
269
class RepositoryFormatKnit(MetaDirRepositoryFormat):
219
270
    """Bzr repository knit format (generalized).
220
271
 
221
272
    This repository format has:
238
289
    _commit_builder_class = None
239
290
    # Set this attribute in derived clases to control the _serializer that the
240
291
    # repository objects will have passed to their constructor.
241
 
 
242
292
    @property
243
293
    def _serializer(self):
244
294
        return xml5.serializer_v5
251
301
    _fetch_order = 'topological'
252
302
    _fetch_uses_deltas = True
253
303
    fast_deltas = False
254
 
    supports_funky_characters = True
255
 
    # The revision.kndx could potentially claim a revision has a different
256
 
    # parent to the revision text.
257
 
    revision_graph_can_have_wrong_parents = True
258
304
 
259
305
    def _get_inventories(self, repo_transport, repo, name='inventory'):
260
306
        mapper = versionedfile.ConstantMapper(name)
261
307
        index = _mod_knit._KndxIndex(repo_transport, mapper,
262
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
308
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
263
309
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
264
310
        return _mod_knit.KnitVersionedFiles(index, access, annotated=False)
265
311
 
266
312
    def _get_revisions(self, repo_transport, repo):
267
313
        mapper = versionedfile.ConstantMapper('revisions')
268
314
        index = _mod_knit._KndxIndex(repo_transport, mapper,
269
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
315
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
270
316
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
271
317
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
272
 
                                            annotated=False)
 
318
            annotated=False)
273
319
 
274
320
    def _get_signatures(self, repo_transport, repo):
275
321
        mapper = versionedfile.ConstantMapper('signatures')
276
322
        index = _mod_knit._KndxIndex(repo_transport, mapper,
277
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
323
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
278
324
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
279
325
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
280
 
                                            annotated=False)
 
326
            annotated=False)
281
327
 
282
328
    def _get_texts(self, repo_transport, repo):
283
329
        mapper = versionedfile.HashEscapedPrefixMapper()
284
330
        base_transport = repo_transport.clone('knits')
285
331
        index = _mod_knit._KndxIndex(base_transport, mapper,
286
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
332
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
287
333
        access = _mod_knit._KnitKeyAccess(base_transport, mapper)
288
334
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=200,
289
 
                                            annotated=True)
 
335
            annotated=True)
290
336
 
291
 
    def initialize(self, a_controldir, shared=False):
 
337
    def initialize(self, a_bzrdir, shared=False):
292
338
        """Create a knit format 1 repository.
293
339
 
294
 
        :param a_controldir: bzrdir to contain the new repository; must already
 
340
        :param a_bzrdir: bzrdir to contain the new repository; must already
295
341
            be initialized.
296
342
        :param shared: If true the repository will be initialized as a shared
297
343
                       repository.
298
344
        """
299
 
        trace.mutter('creating repository in %s.', a_controldir.transport.base)
 
345
        trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
300
346
        dirs = ['knits']
301
347
        files = []
302
348
        utf8_files = [('format', self.get_format_string())]
303
349
 
304
 
        self._upload_blank_content(
305
 
            a_controldir, dirs, files, utf8_files, shared)
306
 
        repo_transport = a_controldir.get_repository_transport(None)
 
350
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
 
351
        repo_transport = a_bzrdir.get_repository_transport(None)
307
352
        control_files = lockable_files.LockableFiles(repo_transport,
308
 
                                                     'lock', lockdir.LockDir)
 
353
                                'lock', lockdir.LockDir)
309
354
        transaction = transactions.WriteTransaction()
310
 
        result = self.open(a_controldir=a_controldir, _found=True)
 
355
        result = self.open(a_bzrdir=a_bzrdir, _found=True)
311
356
        result.lock_write()
312
357
        # the revision id here is irrelevant: it will not be stored, and cannot
313
358
        # already exist, we do this to create files on disk for older clients.
314
 
        result.inventories.get_parent_map([(b'A',)])
315
 
        result.revisions.get_parent_map([(b'A',)])
316
 
        result.signatures.get_parent_map([(b'A',)])
 
359
        result.inventories.get_parent_map([('A',)])
 
360
        result.revisions.get_parent_map([('A',)])
 
361
        result.signatures.get_parent_map([('A',)])
317
362
        result.unlock()
318
 
        self._run_post_repo_init_hooks(result, a_controldir, shared)
 
363
        self._run_post_repo_init_hooks(result, a_bzrdir, shared)
319
364
        return result
320
365
 
321
 
    def open(self, a_controldir, _found=False, _override_transport=None):
 
366
    def open(self, a_bzrdir, _found=False, _override_transport=None):
322
367
        """See RepositoryFormat.open().
323
368
 
324
369
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
326
371
                                    than normal. I.e. during 'upgrade'.
327
372
        """
328
373
        if not _found:
329
 
            format = RepositoryFormatMetaDir.find_format(a_controldir)
 
374
            format = RepositoryFormat.find_format(a_bzrdir)
330
375
        if _override_transport is not None:
331
376
            repo_transport = _override_transport
332
377
        else:
333
 
            repo_transport = a_controldir.get_repository_transport(None)
 
378
            repo_transport = a_bzrdir.get_repository_transport(None)
334
379
        control_files = lockable_files.LockableFiles(repo_transport,
335
 
                                                     'lock', lockdir.LockDir)
 
380
                                'lock', lockdir.LockDir)
336
381
        repo = self.repository_class(_format=self,
337
 
                                     a_controldir=a_controldir,
338
 
                                     control_files=control_files,
339
 
                                     _commit_builder_class=self._commit_builder_class,
340
 
                                     _serializer=self._serializer)
 
382
                              a_bzrdir=a_bzrdir,
 
383
                              control_files=control_files,
 
384
                              _commit_builder_class=self._commit_builder_class,
 
385
                              _serializer=self._serializer)
341
386
        repo.revisions = self._get_revisions(repo_transport, repo)
342
387
        repo.signatures = self._get_signatures(repo_transport, repo)
343
388
        repo.inventories = self._get_inventories(repo_transport, repo)
364
409
    """
365
410
 
366
411
    repository_class = KnitRepository
367
 
    _commit_builder_class = VersionedFileCommitBuilder
368
 
 
 
412
    _commit_builder_class = CommitBuilder
369
413
    @property
370
414
    def _serializer(self):
371
415
        return xml5.serializer_v5
373
417
    def __ne__(self, other):
374
418
        return self.__class__ is not other.__class__
375
419
 
376
 
    @classmethod
377
 
    def get_format_string(cls):
 
420
    def get_format_string(self):
378
421
        """See RepositoryFormat.get_format_string()."""
379
 
        return b"Bazaar-NG Knit Repository Format 1"
 
422
        return "Bazaar-NG Knit Repository Format 1"
380
423
 
381
424
    def get_format_description(self):
382
425
        """See RepositoryFormat.get_format_description()."""
400
443
    """
401
444
 
402
445
    repository_class = KnitRepository
403
 
    _commit_builder_class = VersionedFileCommitBuilder
 
446
    _commit_builder_class = RootCommitBuilder
404
447
    rich_root_data = True
405
448
    experimental = True
406
449
    supports_tree_reference = True
407
 
 
408
450
    @property
409
451
    def _serializer(self):
410
452
        return xml7.serializer_v7
411
453
 
412
454
    def _get_matching_bzrdir(self):
413
 
        return controldir.format_registry.make_controldir('dirstate-with-subtree')
 
455
        return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
414
456
 
415
457
    def _ignore_setting_bzrdir(self, format):
416
458
        pass
417
459
 
418
 
    _matchingcontroldir = property(
419
 
        _get_matching_bzrdir, _ignore_setting_bzrdir)
 
460
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
420
461
 
421
 
    @classmethod
422
 
    def get_format_string(cls):
 
462
    def get_format_string(self):
423
463
        """See RepositoryFormat.get_format_string()."""
424
 
        return b"Bazaar Knit Repository Format 3 (bzr 0.15)\n"
 
464
        return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
425
465
 
426
466
    def get_format_description(self):
427
467
        """See RepositoryFormat.get_format_description()."""
445
485
    """
446
486
 
447
487
    repository_class = KnitRepository
448
 
    _commit_builder_class = VersionedFileCommitBuilder
 
488
    _commit_builder_class = RootCommitBuilder
449
489
    rich_root_data = True
450
490
    supports_tree_reference = False
451
 
 
452
491
    @property
453
492
    def _serializer(self):
454
493
        return xml6.serializer_v6
455
494
 
456
495
    def _get_matching_bzrdir(self):
457
 
        return controldir.format_registry.make_controldir('rich-root')
 
496
        return bzrdir.format_registry.make_bzrdir('rich-root')
458
497
 
459
498
    def _ignore_setting_bzrdir(self, format):
460
499
        pass
461
500
 
462
 
    _matchingcontroldir = property(
463
 
        _get_matching_bzrdir, _ignore_setting_bzrdir)
 
501
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
464
502
 
465
 
    @classmethod
466
 
    def get_format_string(cls):
 
503
    def get_format_string(self):
467
504
        """See RepositoryFormat.get_format_string()."""
468
 
        return b'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
 
505
        return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
469
506
 
470
507
    def get_format_description(self):
471
508
        """See RepositoryFormat.get_format_description()."""
472
509
        return "Knit repository format 4"
473
 
 
474
 
 
475
 
class InterKnitRepo(InterSameDataRepository):
476
 
    """Optimised code paths between Knit based repositories."""
477
 
 
478
 
    @classmethod
479
 
    def _get_repo_format_to_test(self):
480
 
        return RepositoryFormatKnit1()
481
 
 
482
 
    @staticmethod
483
 
    def is_compatible(source, target):
484
 
        """Be compatible with known Knit formats.
485
 
 
486
 
        We don't test for the stores being of specific types because that
487
 
        could lead to confusing results, and there is no need to be
488
 
        overly general.
489
 
        """
490
 
        try:
491
 
            are_knits = (isinstance(source._format, RepositoryFormatKnit)
492
 
                         and isinstance(target._format, RepositoryFormatKnit))
493
 
        except AttributeError:
494
 
            return False
495
 
        return are_knits and InterRepository._same_model(source, target)
496
 
 
497
 
    def search_missing_revision_ids(self,
498
 
                                    find_ghosts=True, revision_ids=None, if_present_ids=None,
499
 
                                    limit=None):
500
 
        """See InterRepository.search_missing_revision_ids()."""
501
 
        with self.lock_read():
502
 
            source_ids_set = self._present_source_revisions_for(
503
 
                revision_ids, if_present_ids)
504
 
            # source_ids is the worst possible case we may need to pull.
505
 
            # now we want to filter source_ids against what we actually
506
 
            # have in target, but don't try to check for existence where we know
507
 
            # we do not have a revision as that would be pointless.
508
 
            target_ids = set(self.target.all_revision_ids())
509
 
            possibly_present_revisions = target_ids.intersection(
510
 
                source_ids_set)
511
 
            actually_present_revisions = set(
512
 
                self.target._eliminate_revisions_not_present(possibly_present_revisions))
513
 
            required_revisions = source_ids_set.difference(
514
 
                actually_present_revisions)
515
 
            if revision_ids is not None:
516
 
                # we used get_ancestry to determine source_ids then we are assured all
517
 
                # revisions referenced are present as they are installed in topological order.
518
 
                # and the tip revision was validated by get_ancestry.
519
 
                result_set = required_revisions
520
 
            else:
521
 
                # if we just grabbed the possibly available ids, then
522
 
                # we only have an estimate of whats available and need to validate
523
 
                # that against the revision records.
524
 
                result_set = set(
525
 
                    self.source._eliminate_revisions_not_present(required_revisions))
526
 
            if limit is not None:
527
 
                topo_ordered = self.source.get_graph().iter_topo_order(result_set)
528
 
                result_set = set(itertools.islice(topo_ordered, limit))
529
 
            return self.source.revision_ids_to_search_result(result_set)
530
 
 
531
 
 
532
 
InterRepository.register_optimiser(InterKnitRepo)