/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 breezy.reconcile import KnitReconciler
210
 
        with self.lock_write():
211
 
            reconciler = KnitReconciler(self, thorough=thorough)
212
 
            reconciler.reconcile()
213
 
            return reconciler
 
224
        from bzrlib.reconcile import KnitReconciler
 
225
        reconciler = KnitReconciler(self, thorough=thorough)
 
226
        reconciler.reconcile()
 
227
        return reconciler
214
228
 
215
229
    def _make_parents_provider(self):
216
230
        return _KnitsParentsProvider(self.revisions)
217
231
 
218
 
 
219
 
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):
220
270
    """Bzr repository knit format (generalized).
221
271
 
222
272
    This repository format has:
239
289
    _commit_builder_class = None
240
290
    # Set this attribute in derived clases to control the _serializer that the
241
291
    # repository objects will have passed to their constructor.
242
 
 
243
292
    @property
244
293
    def _serializer(self):
245
294
        return xml5.serializer_v5
252
301
    _fetch_order = 'topological'
253
302
    _fetch_uses_deltas = True
254
303
    fast_deltas = False
255
 
    supports_funky_characters = True
256
 
    # The revision.kndx could potentially claim a revision has a different
257
 
    # parent to the revision text.
258
 
    revision_graph_can_have_wrong_parents = True
259
304
 
260
305
    def _get_inventories(self, repo_transport, repo, name='inventory'):
261
306
        mapper = versionedfile.ConstantMapper(name)
262
307
        index = _mod_knit._KndxIndex(repo_transport, mapper,
263
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
308
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
264
309
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
265
310
        return _mod_knit.KnitVersionedFiles(index, access, annotated=False)
266
311
 
267
312
    def _get_revisions(self, repo_transport, repo):
268
313
        mapper = versionedfile.ConstantMapper('revisions')
269
314
        index = _mod_knit._KndxIndex(repo_transport, mapper,
270
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
315
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
271
316
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
272
317
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
273
 
                                            annotated=False)
 
318
            annotated=False)
274
319
 
275
320
    def _get_signatures(self, repo_transport, repo):
276
321
        mapper = versionedfile.ConstantMapper('signatures')
277
322
        index = _mod_knit._KndxIndex(repo_transport, mapper,
278
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
323
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
279
324
        access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
280
325
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
281
 
                                            annotated=False)
 
326
            annotated=False)
282
327
 
283
328
    def _get_texts(self, repo_transport, repo):
284
329
        mapper = versionedfile.HashEscapedPrefixMapper()
285
330
        base_transport = repo_transport.clone('knits')
286
331
        index = _mod_knit._KndxIndex(base_transport, mapper,
287
 
                                     repo.get_transaction, repo.is_write_locked, repo.is_locked)
 
332
            repo.get_transaction, repo.is_write_locked, repo.is_locked)
288
333
        access = _mod_knit._KnitKeyAccess(base_transport, mapper)
289
334
        return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=200,
290
 
                                            annotated=True)
 
335
            annotated=True)
291
336
 
292
 
    def initialize(self, a_controldir, shared=False):
 
337
    def initialize(self, a_bzrdir, shared=False):
293
338
        """Create a knit format 1 repository.
294
339
 
295
 
        :param a_controldir: bzrdir to contain the new repository; must already
 
340
        :param a_bzrdir: bzrdir to contain the new repository; must already
296
341
            be initialized.
297
342
        :param shared: If true the repository will be initialized as a shared
298
343
                       repository.
299
344
        """
300
 
        trace.mutter('creating repository in %s.', a_controldir.transport.base)
 
345
        trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
301
346
        dirs = ['knits']
302
347
        files = []
303
348
        utf8_files = [('format', self.get_format_string())]
304
349
 
305
 
        self._upload_blank_content(
306
 
            a_controldir, dirs, files, utf8_files, shared)
307
 
        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)
308
352
        control_files = lockable_files.LockableFiles(repo_transport,
309
 
                                                     'lock', lockdir.LockDir)
 
353
                                'lock', lockdir.LockDir)
310
354
        transaction = transactions.WriteTransaction()
311
 
        result = self.open(a_controldir=a_controldir, _found=True)
 
355
        result = self.open(a_bzrdir=a_bzrdir, _found=True)
312
356
        result.lock_write()
313
357
        # the revision id here is irrelevant: it will not be stored, and cannot
314
358
        # already exist, we do this to create files on disk for older clients.
315
 
        result.inventories.get_parent_map([(b'A',)])
316
 
        result.revisions.get_parent_map([(b'A',)])
317
 
        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',)])
318
362
        result.unlock()
319
 
        self._run_post_repo_init_hooks(result, a_controldir, shared)
 
363
        self._run_post_repo_init_hooks(result, a_bzrdir, shared)
320
364
        return result
321
365
 
322
 
    def open(self, a_controldir, _found=False, _override_transport=None):
 
366
    def open(self, a_bzrdir, _found=False, _override_transport=None):
323
367
        """See RepositoryFormat.open().
324
368
 
325
369
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
327
371
                                    than normal. I.e. during 'upgrade'.
328
372
        """
329
373
        if not _found:
330
 
            format = RepositoryFormatMetaDir.find_format(a_controldir)
 
374
            format = RepositoryFormat.find_format(a_bzrdir)
331
375
        if _override_transport is not None:
332
376
            repo_transport = _override_transport
333
377
        else:
334
 
            repo_transport = a_controldir.get_repository_transport(None)
 
378
            repo_transport = a_bzrdir.get_repository_transport(None)
335
379
        control_files = lockable_files.LockableFiles(repo_transport,
336
 
                                                     'lock', lockdir.LockDir)
 
380
                                'lock', lockdir.LockDir)
337
381
        repo = self.repository_class(_format=self,
338
 
                                     a_controldir=a_controldir,
339
 
                                     control_files=control_files,
340
 
                                     _commit_builder_class=self._commit_builder_class,
341
 
                                     _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)
342
386
        repo.revisions = self._get_revisions(repo_transport, repo)
343
387
        repo.signatures = self._get_signatures(repo_transport, repo)
344
388
        repo.inventories = self._get_inventories(repo_transport, repo)
365
409
    """
366
410
 
367
411
    repository_class = KnitRepository
368
 
    _commit_builder_class = VersionedFileCommitBuilder
369
 
 
 
412
    _commit_builder_class = CommitBuilder
370
413
    @property
371
414
    def _serializer(self):
372
415
        return xml5.serializer_v5
374
417
    def __ne__(self, other):
375
418
        return self.__class__ is not other.__class__
376
419
 
377
 
    @classmethod
378
 
    def get_format_string(cls):
 
420
    def get_format_string(self):
379
421
        """See RepositoryFormat.get_format_string()."""
380
 
        return b"Bazaar-NG Knit Repository Format 1"
 
422
        return "Bazaar-NG Knit Repository Format 1"
381
423
 
382
424
    def get_format_description(self):
383
425
        """See RepositoryFormat.get_format_description()."""
401
443
    """
402
444
 
403
445
    repository_class = KnitRepository
404
 
    _commit_builder_class = VersionedFileCommitBuilder
 
446
    _commit_builder_class = RootCommitBuilder
405
447
    rich_root_data = True
406
448
    experimental = True
407
449
    supports_tree_reference = True
408
 
 
409
450
    @property
410
451
    def _serializer(self):
411
452
        return xml7.serializer_v7
412
453
 
413
454
    def _get_matching_bzrdir(self):
414
 
        return controldir.format_registry.make_controldir('dirstate-with-subtree')
 
455
        return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
415
456
 
416
457
    def _ignore_setting_bzrdir(self, format):
417
458
        pass
418
459
 
419
 
    _matchingcontroldir = property(
420
 
        _get_matching_bzrdir, _ignore_setting_bzrdir)
 
460
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
421
461
 
422
 
    @classmethod
423
 
    def get_format_string(cls):
 
462
    def get_format_string(self):
424
463
        """See RepositoryFormat.get_format_string()."""
425
 
        return b"Bazaar Knit Repository Format 3 (bzr 0.15)\n"
 
464
        return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
426
465
 
427
466
    def get_format_description(self):
428
467
        """See RepositoryFormat.get_format_description()."""
446
485
    """
447
486
 
448
487
    repository_class = KnitRepository
449
 
    _commit_builder_class = VersionedFileCommitBuilder
 
488
    _commit_builder_class = RootCommitBuilder
450
489
    rich_root_data = True
451
490
    supports_tree_reference = False
452
 
 
453
491
    @property
454
492
    def _serializer(self):
455
493
        return xml6.serializer_v6
456
494
 
457
495
    def _get_matching_bzrdir(self):
458
 
        return controldir.format_registry.make_controldir('rich-root')
 
496
        return bzrdir.format_registry.make_bzrdir('rich-root')
459
497
 
460
498
    def _ignore_setting_bzrdir(self, format):
461
499
        pass
462
500
 
463
 
    _matchingcontroldir = property(
464
 
        _get_matching_bzrdir, _ignore_setting_bzrdir)
 
501
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
465
502
 
466
 
    @classmethod
467
 
    def get_format_string(cls):
 
503
    def get_format_string(self):
468
504
        """See RepositoryFormat.get_format_string()."""
469
 
        return b'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
 
505
        return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
470
506
 
471
507
    def get_format_description(self):
472
508
        """See RepositoryFormat.get_format_description()."""
473
509
        return "Knit repository format 4"
474
 
 
475
 
 
476
 
class InterKnitRepo(InterSameDataRepository):
477
 
    """Optimised code paths between Knit based repositories."""
478
 
 
479
 
    @classmethod
480
 
    def _get_repo_format_to_test(self):
481
 
        return RepositoryFormatKnit1()
482
 
 
483
 
    @staticmethod
484
 
    def is_compatible(source, target):
485
 
        """Be compatible with known Knit formats.
486
 
 
487
 
        We don't test for the stores being of specific types because that
488
 
        could lead to confusing results, and there is no need to be
489
 
        overly general.
490
 
        """
491
 
        try:
492
 
            are_knits = (isinstance(source._format, RepositoryFormatKnit)
493
 
                         and isinstance(target._format, RepositoryFormatKnit))
494
 
        except AttributeError:
495
 
            return False
496
 
        return are_knits and InterRepository._same_model(source, target)
497
 
 
498
 
    def search_missing_revision_ids(self,
499
 
                                    find_ghosts=True, revision_ids=None, if_present_ids=None,
500
 
                                    limit=None):
501
 
        """See InterRepository.search_missing_revision_ids()."""
502
 
        with self.lock_read():
503
 
            source_ids_set = self._present_source_revisions_for(
504
 
                revision_ids, if_present_ids)
505
 
            # source_ids is the worst possible case we may need to pull.
506
 
            # now we want to filter source_ids against what we actually
507
 
            # have in target, but don't try to check for existence where we know
508
 
            # we do not have a revision as that would be pointless.
509
 
            target_ids = set(self.target.all_revision_ids())
510
 
            possibly_present_revisions = target_ids.intersection(
511
 
                source_ids_set)
512
 
            actually_present_revisions = set(
513
 
                self.target._eliminate_revisions_not_present(possibly_present_revisions))
514
 
            required_revisions = source_ids_set.difference(
515
 
                actually_present_revisions)
516
 
            if revision_ids is not None:
517
 
                # we used get_ancestry to determine source_ids then we are assured all
518
 
                # revisions referenced are present as they are installed in topological order.
519
 
                # and the tip revision was validated by get_ancestry.
520
 
                result_set = required_revisions
521
 
            else:
522
 
                # if we just grabbed the possibly available ids, then
523
 
                # we only have an estimate of whats available and need to validate
524
 
                # that against the revision records.
525
 
                result_set = set(
526
 
                    self.source._eliminate_revisions_not_present(required_revisions))
527
 
            if limit is not None:
528
 
                topo_ordered = self.source.get_graph().iter_topo_order(result_set)
529
 
                result_set = set(itertools.islice(topo_ordered, limit))
530
 
            return self.source.revision_ids_to_search_result(result_set)
531
 
 
532
 
 
533
 
InterRepository.register_optimiser(InterKnitRepo)