/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 breezy/bzr/knitrepo.py

  • Committer: Jelmer Vernooij
  • Date: 2020-08-22 22:46:24 UTC
  • mfrom: (7490.40.105 work)
  • mto: This revision was merged to the branch mainline in revision 7521.
  • Revision ID: jelmer@jelmer.uk-20200822224624-om4a4idsr7cn8jew
merge lp:brz/3.1.

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