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 (
42
MetaDirRepositoryFormat,
41
from ..repository import (
45
from ..bzr.repository import (
46
RepositoryFormatMetaDir,
48
from ..bzr.vf_repository import (
49
InterSameDataRepository,
50
MetaDirVersionedFileRepository,
51
MetaDirVersionedFileRepositoryFormat,
52
VersionedFileCommitBuilder,
112
120
_commit_builder_class = None
113
121
_serializer = None
115
def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
123
def __init__(self, _format, a_controldir, control_files, _commit_builder_class,
117
MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
125
super(KnitRepository, self).__init__(_format, a_controldir, control_files)
118
126
self._commit_builder_class = _commit_builder_class
119
127
self._serializer = _serializer
120
128
self._reconcile_fixes_text_parents = True
123
130
def _all_revision_ids(self):
124
131
"""See Repository.all_revision_ids()."""
125
return [key[0] for key in self.revisions.keys()]
132
with self.lock_read():
133
return [key[0] for key in self.revisions.keys()]
127
135
def _activate_new_inventory(self):
128
136
"""Put a replacement inventory.new into use as inventories."""
173
181
# Reconciling when the output has no revisions would result in no
174
182
# writes - but we want to ensure there is an inventory for
175
183
# compatibility with older clients that don't lazy-load.
176
result.get_parent_map([('A',)])
184
result.get_parent_map([(b'A',)])
179
def fileid_involved_between_revs(self, from_revid, to_revid):
180
"""Find file_id(s) which are involved in the changes between revisions.
182
This determines the set of revisions which are involved, and then
183
finds all file ids affected by those revisions.
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)
191
def fileid_involved(self, last_revid=None):
192
"""Find all file_ids modified in the ancestry of last_revid.
194
:param last_revid: If None, last_revision() will be used.
197
changed = set(self.all_revision_ids())
199
changed = set(self.get_ancestry(last_revid))
202
return self._fileid_involved_by_set(changed)
205
187
def get_revision(self, revision_id):
206
188
"""Return the Revision object for a named revision"""
207
189
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)
210
193
def _refresh_data(self):
211
194
if not self.is_locked():
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()
219
204
self.control_files._set_read_transaction()
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()
208
from breezy.reconcile import KnitReconciler
209
with self.lock_write():
210
reconciler = KnitReconciler(self, thorough=thorough)
211
reconciler.reconcile()
229
214
def _make_parents_provider(self):
230
215
return _KnitsParentsProvider(self.revisions)
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.
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).
241
if not self.is_locked():
242
raise AssertionError()
244
if revisions_iterator is None:
245
revisions_iterator = self._iter_revisions(None)
246
for revid, revision in revisions_iterator:
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)
257
def _check_for_inconsistent_revision_parents(self):
258
inconsistencies = list(self._find_inconsistent_revision_parents())
260
raise errors.BzrCheckError(
261
"Revision knit has inconsistent parents.")
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.
269
class RepositoryFormatKnit(MetaDirRepositoryFormat):
218
class RepositoryFormatKnit(MetaDirVersionedFileRepositoryFormat):
270
219
"""Bzr repository knit format (generalized).
272
221
This repository format has:
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
305
258
def _get_inventories(self, repo_transport, repo, name='inventory'):
306
259
mapper = versionedfile.ConstantMapper(name)
334
287
return _mod_knit.KnitVersionedFiles(index, access, max_delta_chain=200,
337
def initialize(self, a_bzrdir, shared=False):
290
def initialize(self, a_controldir, shared=False):
338
291
"""Create a knit format 1 repository.
340
:param a_bzrdir: bzrdir to contain the new repository; must already
293
:param a_controldir: bzrdir to contain the new repository; must already
342
295
:param shared: If true the repository will be initialized as a shared
345
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
298
trace.mutter('creating repository in %s.', a_controldir.transport.base)
348
301
utf8_files = [('format', self.get_format_string())]
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(a_controldir, dirs, files, utf8_files, shared)
304
repo_transport = a_controldir.get_repository_transport(None)
352
305
control_files = lockable_files.LockableFiles(repo_transport,
353
306
'lock', lockdir.LockDir)
354
307
transaction = transactions.WriteTransaction()
355
result = self.open(a_bzrdir=a_bzrdir, _found=True)
308
result = self.open(a_controldir=a_controldir, _found=True)
356
309
result.lock_write()
357
310
# the revision id here is irrelevant: it will not be stored, and cannot
358
311
# 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',)])
312
result.inventories.get_parent_map([(b'A',)])
313
result.revisions.get_parent_map([(b'A',)])
314
result.signatures.get_parent_map([(b'A',)])
363
self._run_post_repo_init_hooks(result, a_bzrdir, shared)
316
self._run_post_repo_init_hooks(result, a_controldir, shared)
366
def open(self, a_bzrdir, _found=False, _override_transport=None):
319
def open(self, a_controldir, _found=False, _override_transport=None):
367
320
"""See RepositoryFormat.open().
369
322
:param _override_transport: INTERNAL USE ONLY. Allows opening the
371
324
than normal. I.e. during 'upgrade'.
374
format = RepositoryFormat.find_format(a_bzrdir)
327
format = RepositoryFormatMetaDir.find_format(a_controldir)
375
328
if _override_transport is not None:
376
329
repo_transport = _override_transport
378
repo_transport = a_bzrdir.get_repository_transport(None)
331
repo_transport = a_controldir.get_repository_transport(None)
379
332
control_files = lockable_files.LockableFiles(repo_transport,
380
333
'lock', lockdir.LockDir)
381
334
repo = self.repository_class(_format=self,
335
a_controldir=a_controldir,
383
336
control_files=control_files,
384
337
_commit_builder_class=self._commit_builder_class,
385
338
_serializer=self._serializer)
452
406
return xml7.serializer_v7
454
408
def _get_matching_bzrdir(self):
455
return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
409
return controldir.format_registry.make_controldir('dirstate-with-subtree')
457
411
def _ignore_setting_bzrdir(self, format):
460
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
414
_matchingcontroldir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
462
def get_format_string(self):
417
def get_format_string(cls):
463
418
"""See RepositoryFormat.get_format_string()."""
464
return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
419
return b"Bazaar Knit Repository Format 3 (bzr 0.15)\n"
466
421
def get_format_description(self):
467
422
"""See RepositoryFormat.get_format_description()."""
493
448
return xml6.serializer_v6
495
450
def _get_matching_bzrdir(self):
496
return bzrdir.format_registry.make_bzrdir('rich-root')
451
return controldir.format_registry.make_controldir('rich-root')
498
453
def _ignore_setting_bzrdir(self, format):
501
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
456
_matchingcontroldir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
503
def get_format_string(self):
459
def get_format_string(cls):
504
460
"""See RepositoryFormat.get_format_string()."""
505
return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
461
return b'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
507
463
def get_format_description(self):
508
464
"""See RepositoryFormat.get_format_description()."""
509
465
return "Knit repository format 4"
468
class InterKnitRepo(InterSameDataRepository):
469
"""Optimised code paths between Knit based repositories."""
472
def _get_repo_format_to_test(self):
473
return RepositoryFormatKnit1()
476
def is_compatible(source, target):
477
"""Be compatible with known Knit formats.
479
We don't test for the stores being of specific types because that
480
could lead to confusing results, and there is no need to be
484
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
485
isinstance(target._format, RepositoryFormatKnit))
486
except AttributeError:
488
return are_knits and InterRepository._same_model(source, target)
490
def search_missing_revision_ids(self,
491
find_ghosts=True, revision_ids=None, if_present_ids=None,
493
"""See InterRepository.search_missing_revision_ids()."""
494
with self.lock_read():
495
source_ids_set = self._present_source_revisions_for(
496
revision_ids, if_present_ids)
497
# source_ids is the worst possible case we may need to pull.
498
# now we want to filter source_ids against what we actually
499
# have in target, but don't try to check for existence where we know
500
# we do not have a revision as that would be pointless.
501
target_ids = set(self.target.all_revision_ids())
502
possibly_present_revisions = target_ids.intersection(source_ids_set)
503
actually_present_revisions = set(
504
self.target._eliminate_revisions_not_present(possibly_present_revisions))
505
required_revisions = source_ids_set.difference(actually_present_revisions)
506
if revision_ids is not None:
507
# we used get_ancestry to determine source_ids then we are assured all
508
# revisions referenced are present as they are installed in topological order.
509
# and the tip revision was validated by get_ancestry.
510
result_set = required_revisions
512
# if we just grabbed the possibly available ids, then
513
# we only have an estimate of whats available and need to validate
514
# that against the revision records.
516
self.source._eliminate_revisions_not_present(required_revisions))
517
if limit is not None:
518
topo_ordered = self.source.get_graph().iter_topo_order(result_set)
519
result_set = set(itertools.islice(topo_ordered, limit))
520
return self.source.revision_ids_to_search_result(result_set)
523
InterRepository.register_optimiser(InterKnitRepo)