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
17
from bzrlib.lazy_import import lazy_import
17
from __future__ import absolute_import
19
from ..lazy_import import lazy_import
18
20
lazy_import(globals(), """
26
29
revision as _mod_revision,
33
from breezy.bzr import (
38
from bzrlib.decorators import needs_read_lock, needs_write_lock
39
from bzrlib.repository import (
41
from ..repository import (
41
43
IsInWriteGroupError,
43
MetaDirRepositoryFormat,
45
from ..bzr.repository import (
46
RepositoryFormatMetaDir,
48
from ..bzr.vf_repository import (
49
InterSameDataRepository,
50
MetaDirVersionedFileRepository,
51
MetaDirVersionedFileRepositoryFormat,
52
VersionedFileCommitBuilder,
113
120
_commit_builder_class = None
114
121
_serializer = None
116
def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
118
MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
123
def __init__(self, _format, a_controldir, control_files, _commit_builder_class,
125
super(KnitRepository, self).__init__(
126
_format, a_controldir, control_files)
119
127
self._commit_builder_class = _commit_builder_class
120
128
self._serializer = _serializer
121
129
self._reconcile_fixes_text_parents = True
124
131
def _all_revision_ids(self):
125
132
"""See Repository.all_revision_ids()."""
126
return [key[0] for key in self.revisions.keys()]
133
with self.lock_read():
134
return [key[0] for key in self.revisions.keys()]
128
136
def _activate_new_inventory(self):
129
137
"""Put a replacement inventory.new into use as inventories."""
171
179
def _temp_inventories(self):
172
180
result = self._format._get_inventories(self._transport, self,
174
182
# Reconciling when the output has no revisions would result in no
175
183
# writes - but we want to ensure there is an inventory for
176
184
# compatibility with older clients that don't lazy-load.
177
result.get_parent_map([('A',)])
185
result.get_parent_map([(b'A',)])
180
def fileid_involved_between_revs(self, from_revid, to_revid):
181
"""Find file_id(s) which are involved in the changes between revisions.
183
This determines the set of revisions which are involved, and then
184
finds all file ids affected by those revisions.
186
vf = self._get_revision_vf()
187
from_set = set(vf.get_ancestry(from_revid))
188
to_set = set(vf.get_ancestry(to_revid))
189
changed = to_set.difference(from_set)
190
return self._fileid_involved_by_set(changed)
192
def fileid_involved(self, last_revid=None):
193
"""Find all file_ids modified in the ancestry of last_revid.
195
:param last_revid: If None, last_revision() will be used.
198
changed = set(self.all_revision_ids())
200
changed = set(self.get_ancestry(last_revid))
203
return self._fileid_involved_by_set(changed)
206
188
def get_revision(self, revision_id):
207
189
"""Return the Revision object for a named revision"""
208
190
revision_id = osutils.safe_revision_id(revision_id)
209
return self.get_revision_reconcile(revision_id)
191
with self.lock_read():
192
return self.get_revision_reconcile(revision_id)
211
194
def _refresh_data(self):
212
195
if not self.is_locked():
222
205
self.control_files._set_read_transaction()
225
207
def reconcile(self, other=None, thorough=False):
226
208
"""Reconcile this repository."""
227
from bzrlib.reconcile import KnitReconciler
228
reconciler = KnitReconciler(self, thorough=thorough)
229
reconciler.reconcile()
209
from .reconcile import KnitReconciler
210
with self.lock_write():
211
reconciler = KnitReconciler(self, thorough=thorough)
212
return reconciler.reconcile()
232
214
def _make_parents_provider(self):
233
215
return _KnitsParentsProvider(self.revisions)
235
def _find_inconsistent_revision_parents(self, revisions_iterator=None):
236
"""Find revisions with different parent lists in the revision object
237
and in the index graph.
239
:param revisions_iterator: None, or an iterator of (revid,
240
Revision-or-None). This iterator controls the revisions checked.
241
:returns: an iterator yielding tuples of (revison-id, parents-in-index,
242
parents-in-revision).
244
if not self.is_locked():
245
raise AssertionError()
247
if revisions_iterator is None:
248
revisions_iterator = self._iter_revisions(None)
249
for revid, revision in revisions_iterator:
252
parent_map = vf.get_parent_map([(revid,)])
253
parents_according_to_index = tuple(parent[-1] for parent in
254
parent_map[(revid,)])
255
parents_according_to_revision = tuple(revision.parent_ids)
256
if parents_according_to_index != parents_according_to_revision:
257
yield (revid, parents_according_to_index,
258
parents_according_to_revision)
260
def _check_for_inconsistent_revision_parents(self):
261
inconsistencies = list(self._find_inconsistent_revision_parents())
263
raise errors.BzrCheckError(
264
"Revision knit has inconsistent parents.")
266
def revision_graph_can_have_wrong_parents(self):
267
# The revision.kndx could potentially claim a revision has a different
268
# parent to the revision text.
272
class RepositoryFormatKnit(MetaDirRepositoryFormat):
218
class RepositoryFormatKnit(MetaDirVersionedFileRepositoryFormat):
273
219
"""Bzr repository knit format (generalized).
275
221
This repository format has:
304
251
_fetch_order = 'topological'
305
252
_fetch_uses_deltas = True
306
253
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
308
259
def _get_inventories(self, repo_transport, repo, name='inventory'):
309
260
mapper = versionedfile.ConstantMapper(name)
310
261
index = _mod_knit._KndxIndex(repo_transport, mapper,
311
repo.get_transaction, repo.is_write_locked, repo.is_locked)
262
repo.get_transaction, repo.is_write_locked, repo.is_locked)
312
263
access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
313
264
return _mod_knit.KnitVersionedFiles(index, access, annotated=False)
315
266
def _get_revisions(self, repo_transport, repo):
316
267
mapper = versionedfile.ConstantMapper('revisions')
317
268
index = _mod_knit._KndxIndex(repo_transport, mapper,
318
repo.get_transaction, repo.is_write_locked, repo.is_locked)
269
repo.get_transaction, repo.is_write_locked, repo.is_locked)
319
270
access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
320
271
return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
323
274
def _get_signatures(self, repo_transport, repo):
324
275
mapper = versionedfile.ConstantMapper('signatures')
325
276
index = _mod_knit._KndxIndex(repo_transport, mapper,
326
repo.get_transaction, repo.is_write_locked, repo.is_locked)
277
repo.get_transaction, repo.is_write_locked, repo.is_locked)
327
278
access = _mod_knit._KnitKeyAccess(repo_transport, mapper)
328
279
return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=0,
331
282
def _get_texts(self, repo_transport, repo):
332
283
mapper = versionedfile.HashEscapedPrefixMapper()
333
284
base_transport = repo_transport.clone('knits')
334
285
index = _mod_knit._KndxIndex(base_transport, mapper,
335
repo.get_transaction, repo.is_write_locked, repo.is_locked)
286
repo.get_transaction, repo.is_write_locked, repo.is_locked)
336
287
access = _mod_knit._KnitKeyAccess(base_transport, mapper)
337
288
return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=200,
340
def initialize(self, a_bzrdir, shared=False):
291
def initialize(self, a_controldir, shared=False):
341
292
"""Create a knit format 1 repository.
343
:param a_bzrdir: bzrdir to contain the new repository; must already
294
:param a_controldir: bzrdir to contain the new repository; must already
345
296
:param shared: If true the repository will be initialized as a shared
348
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
299
trace.mutter('creating repository in %s.', a_controldir.transport.base)
351
302
utf8_files = [('format', self.get_format_string())]
353
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
354
repo_transport = a_bzrdir.get_repository_transport(None)
304
self._upload_blank_content(
305
a_controldir, dirs, files, utf8_files, shared)
306
repo_transport = a_controldir.get_repository_transport(None)
355
307
control_files = lockable_files.LockableFiles(repo_transport,
356
'lock', lockdir.LockDir)
308
'lock', lockdir.LockDir)
357
309
transaction = transactions.WriteTransaction()
358
result = self.open(a_bzrdir=a_bzrdir, _found=True)
310
result = self.open(a_controldir=a_controldir, _found=True)
359
311
result.lock_write()
360
312
# the revision id here is irrelevant: it will not be stored, and cannot
361
313
# already exist, we do this to create files on disk for older clients.
362
result.inventories.get_parent_map([('A',)])
363
result.revisions.get_parent_map([('A',)])
364
result.signatures.get_parent_map([('A',)])
314
result.inventories.get_parent_map([(b'A',)])
315
result.revisions.get_parent_map([(b'A',)])
316
result.signatures.get_parent_map([(b'A',)])
366
self._run_post_repo_init_hooks(result, a_bzrdir, shared)
318
self._run_post_repo_init_hooks(result, a_controldir, shared)
369
def open(self, a_bzrdir, _found=False, _override_transport=None):
321
def open(self, a_controldir, _found=False, _override_transport=None):
370
322
"""See RepositoryFormat.open().
372
324
:param _override_transport: INTERNAL USE ONLY. Allows opening the
374
326
than normal. I.e. during 'upgrade'.
377
format = RepositoryFormat.find_format(a_bzrdir)
329
format = RepositoryFormatMetaDir.find_format(a_controldir)
378
330
if _override_transport is not None:
379
331
repo_transport = _override_transport
381
repo_transport = a_bzrdir.get_repository_transport(None)
333
repo_transport = a_controldir.get_repository_transport(None)
382
334
control_files = lockable_files.LockableFiles(repo_transport,
383
'lock', lockdir.LockDir)
335
'lock', lockdir.LockDir)
384
336
repo = self.repository_class(_format=self,
386
control_files=control_files,
387
_commit_builder_class=self._commit_builder_class,
388
_serializer=self._serializer)
337
a_controldir=a_controldir,
338
control_files=control_files,
339
_commit_builder_class=self._commit_builder_class,
340
_serializer=self._serializer)
389
341
repo.revisions = self._get_revisions(repo_transport, repo)
390
342
repo.signatures = self._get_signatures(repo_transport, repo)
391
343
repo.inventories = self._get_inventories(repo_transport, repo)
448
402
repository_class = KnitRepository
449
_commit_builder_class = RootCommitBuilder
403
_commit_builder_class = VersionedFileCommitBuilder
450
404
rich_root_data = True
451
405
experimental = True
452
406
supports_tree_reference = True
454
409
def _serializer(self):
455
410
return xml7.serializer_v7
457
412
def _get_matching_bzrdir(self):
458
return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
413
return controldir.format_registry.make_controldir('dirstate-with-subtree')
460
415
def _ignore_setting_bzrdir(self, format):
463
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
418
_matchingcontroldir = property(
419
_get_matching_bzrdir, _ignore_setting_bzrdir)
465
def get_format_string(self):
422
def get_format_string(cls):
466
423
"""See RepositoryFormat.get_format_string()."""
467
return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
424
return b"Bazaar Knit Repository Format 3 (bzr 0.15)\n"
469
426
def get_format_description(self):
470
427
"""See RepositoryFormat.get_format_description()."""
490
447
repository_class = KnitRepository
491
_commit_builder_class = RootCommitBuilder
448
_commit_builder_class = VersionedFileCommitBuilder
492
449
rich_root_data = True
493
450
supports_tree_reference = False
495
453
def _serializer(self):
496
454
return xml6.serializer_v6
498
456
def _get_matching_bzrdir(self):
499
return bzrdir.format_registry.make_bzrdir('rich-root')
457
return controldir.format_registry.make_controldir('rich-root')
501
459
def _ignore_setting_bzrdir(self, format):
504
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
462
_matchingcontroldir = property(
463
_get_matching_bzrdir, _ignore_setting_bzrdir)
506
def get_format_string(self):
466
def get_format_string(cls):
507
467
"""See RepositoryFormat.get_format_string()."""
508
return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
468
return b'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
510
470
def get_format_description(self):
511
471
"""See RepositoryFormat.get_format_description()."""
512
472
return "Knit repository format 4"
475
class InterKnitRepo(InterSameDataRepository):
476
"""Optimised code paths between Knit based repositories."""
479
def _get_repo_format_to_test(self):
480
return RepositoryFormatKnit1()
483
def is_compatible(source, target):
484
"""Be compatible with known Knit formats.
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
491
are_knits = (isinstance(source._format, RepositoryFormatKnit)
492
and isinstance(target._format, RepositoryFormatKnit))
493
except AttributeError:
495
return are_knits and InterRepository._same_model(source, target)
497
def search_missing_revision_ids(self,
498
find_ghosts=True, revision_ids=None, if_present_ids=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(
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
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.
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)
532
InterRepository.register_optimiser(InterKnitRepo)