1109
1112
def _resume_write_group(self, tokens):
1110
1113
raise errors.UnsuspendableWriteGroup(self)
1112
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False):
1115
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1113
1117
"""Fetch the content required to construct revision_id from source.
1115
If revision_id is None all content is copied.
1119
If revision_id is None and fetch_spec is None, then all content is
1122
fetch() may not be used when the repository is in a write group -
1123
either finish the current write group before using fetch, or use
1124
fetch before starting the write group.
1116
1126
:param find_ghosts: Find and copy revisions in the source that are
1117
1127
ghosts in the target (and not reachable directly by walking out to
1118
1128
the first-present revision in target from revision_id).
1129
:param revision_id: If specified, all the content needed for this
1130
revision ID will be copied to the target. Fetch will determine for
1131
itself which content needs to be copied.
1132
:param fetch_spec: If specified, a SearchResult or
1133
PendingAncestryResult that describes which revisions to copy. This
1134
allows copying multiple heads at once. Mutually exclusive with
1137
if fetch_spec is not None and revision_id is not None:
1138
raise AssertionError(
1139
"fetch_spec and revision_id are mutually exclusive.")
1140
if self.is_in_write_group():
1141
raise errors.InternalBzrError(
1142
"May not fetch while in a write group.")
1120
1143
# fast path same-url fetch operations
1121
if self.has_same_location(source):
1144
if self.has_same_location(source) and fetch_spec is None:
1122
1145
# check that last_revision is in 'from' and then return a
1123
1146
# no-operation.
1124
1147
if (revision_id is not None and
1464
1508
revision_ids. Each altered file-ids has the exact revision_ids that
1465
1509
altered it listed explicitly.
1511
seen = set(self._find_text_key_references_from_xml_inventory_lines(
1512
line_iterator).iterkeys())
1513
# Note that revision_ids are revision keys.
1514
parent_maps = self.revisions.get_parent_map(revision_ids)
1516
map(parents.update, parent_maps.itervalues())
1517
parents.difference_update(revision_ids)
1518
parent_seen = set(self._find_text_key_references_from_xml_inventory_lines(
1519
self._inventory_xml_lines_for_keys(parents)))
1520
new_keys = seen - parent_seen
1468
1522
setdefault = result.setdefault
1470
self._find_text_key_references_from_xml_inventory_lines(
1471
line_iterator).iterkeys():
1472
# once data is all ensured-consistent; then this is
1473
# if revision_id == version_id
1474
if key[-1:] in revision_ids:
1475
setdefault(key[0], set()).add(key[-1])
1523
for key in new_keys:
1524
setdefault(key[0], set()).add(key[-1])
1478
1527
def fileids_altered_by_revision_ids(self, revision_ids, _inv_weave=None):
2549
2622
InterRepository.get(other).method_name(parameters).
2552
_walk_to_common_revisions_batch_size = 1
2625
_walk_to_common_revisions_batch_size = 50
2553
2626
_optimisers = []
2554
2627
"""The available optimised InterRepository types."""
2556
def __init__(self, source, target):
2557
InterObject.__init__(self, source, target)
2558
# These two attributes may be overridden by e.g. InterOtherToRemote to
2559
# provide a faster implementation.
2560
self.target_get_graph = self.target.get_graph
2561
self.target_get_parent_map = self.target.get_parent_map
2563
2630
def copy_content(self, revision_id=None):
2564
raise NotImplementedError(self.copy_content)
2566
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2631
"""Make a complete copy of the content in self into destination.
2633
This is a destructive operation! Do not use it on existing
2636
:param revision_id: Only copy the content needed to construct
2637
revision_id and its parents.
2640
self.target.set_make_working_trees(self.source.make_working_trees())
2641
except NotImplementedError:
2643
self.target.fetch(self.source, revision_id=revision_id)
2646
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
2567
2648
"""Fetch the content required to construct revision_id.
2569
2650
The content is copied from self.source to self.target.
2572
2653
content is copied.
2573
2654
:param pb: optional progress bar to use for progress reports. If not
2574
2655
provided a default one will be created.
2576
:returns: (copied_revision_count, failures).
2578
# Normally we should find a specific InterRepository subclass to do
2579
# the fetch; if nothing else then at least InterSameDataRepository.
2580
# If none of them is suitable it looks like fetching is not possible;
2581
# we try to give a good message why. _assert_same_model will probably
2582
# give a helpful message; otherwise a generic one.
2583
self._assert_same_model(self.source, self.target)
2584
raise errors.IncompatibleRepositories(self.source, self.target,
2585
"no suitableInterRepository found")
2658
from bzrlib.fetch import RepoFetcher
2659
f = RepoFetcher(to_repository=self.target,
2660
from_repository=self.source,
2661
last_revision=revision_id,
2662
fetch_spec=fetch_spec,
2663
pb=pb, find_ghosts=find_ghosts)
2587
2665
def _walk_to_common_revisions(self, revision_ids):
2588
2666
"""Walk out from revision_ids in source to revisions target has.
2728
2806
def is_compatible(source, target):
2729
2807
return InterRepository._same_model(source, target)
2732
def copy_content(self, revision_id=None):
2733
"""Make a complete copy of the content in self into destination.
2735
This copies both the repository's revision data, and configuration information
2736
such as the make_working_trees setting.
2738
This is a destructive operation! Do not use it on existing
2741
:param revision_id: Only copy the content needed to construct
2742
revision_id and its parents.
2745
self.target.set_make_working_trees(self.source.make_working_trees())
2746
except NotImplementedError:
2748
# but don't bother fetching if we have the needed data now.
2749
if (revision_id not in (None, _mod_revision.NULL_REVISION) and
2750
self.target.has_revision(revision_id)):
2752
self.target.fetch(self.source, revision_id=revision_id)
2755
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2756
"""See InterRepository.fetch()."""
2757
from bzrlib.fetch import RepoFetcher
2758
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
2759
self.source, self.source._format, self.target,
2760
self.target._format)
2761
f = RepoFetcher(to_repository=self.target,
2762
from_repository=self.source,
2763
last_revision=revision_id,
2764
pb=pb, find_ghosts=find_ghosts)
2765
return f.count_copied, f.failed_revisions
2768
2810
class InterWeaveRepo(InterSameDataRepository):
2769
2811
"""Optimised code paths between Weave based repositories.
2833
2875
self.target.fetch(self.source, revision_id=revision_id)
2836
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2837
"""See InterRepository.fetch()."""
2838
from bzrlib.fetch import RepoFetcher
2839
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
2840
self.source, self.source._format, self.target, self.target._format)
2841
f = RepoFetcher(to_repository=self.target,
2842
from_repository=self.source,
2843
last_revision=revision_id,
2844
pb=pb, find_ghosts=find_ghosts)
2845
return f.count_copied, f.failed_revisions
2847
2877
@needs_read_lock
2848
2878
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2849
2879
"""See InterRepository.missing_revision_ids()."""
2914
2944
return are_knits and InterRepository._same_model(source, target)
2917
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
2918
"""See InterRepository.fetch()."""
2919
from bzrlib.fetch import RepoFetcher
2920
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
2921
self.source, self.source._format, self.target, self.target._format)
2922
f = RepoFetcher(to_repository=self.target,
2923
from_repository=self.source,
2924
last_revision=revision_id,
2925
pb=pb, find_ghosts=find_ghosts)
2926
return f.count_copied, f.failed_revisions
2928
2946
@needs_read_lock
2929
2947
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
2930
2948
"""See InterRepository.missing_revision_ids()."""
3037
3058
def _pack(self, source, target, revision_ids):
3038
3059
from bzrlib.repofmt.pack_repo import Packer
3039
target_pack_collection = self._get_target_pack_collection()
3040
3060
packs = source._pack_collection.all_packs()
3041
pack = Packer(target_pack_collection, packs, '.fetch',
3061
pack = Packer(self.target._pack_collection, packs, '.fetch',
3042
3062
revision_ids).pack()
3043
3063
if pack is not None:
3044
target_pack_collection._save_pack_names()
3064
self.target._pack_collection._save_pack_names()
3045
3065
copied_revs = pack.get_revision_count()
3046
3066
# Trigger an autopack. This may duplicate effort as we've just done
3047
3067
# a pack creation, but for now it is simpler to think about as
3048
3068
# 'upload data, then repack if needed'.
3069
self.target._pack_collection.autopack()
3050
3070
return (copied_revs, [])
3054
def _autopack(self):
3055
self.target._pack_collection.autopack()
3057
def _get_target_pack_collection(self):
3058
return self.target._pack_collection
3060
3074
@needs_read_lock
3061
3075
def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3062
3076
"""See InterRepository.missing_revision_ids().
3097
3111
return self.source.revision_ids_to_search_result(result_set)
3100
class InterModel1and2(InterRepository):
3103
def _get_repo_format_to_test(self):
3107
def is_compatible(source, target):
3108
if not source.supports_rich_root() and target.supports_rich_root():
3114
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
3115
"""See InterRepository.fetch()."""
3116
from bzrlib.fetch import Model1toKnit2Fetcher
3117
f = Model1toKnit2Fetcher(to_repository=self.target,
3118
from_repository=self.source,
3119
last_revision=revision_id,
3120
pb=pb, find_ghosts=find_ghosts)
3121
return f.count_copied, f.failed_revisions
3124
def copy_content(self, revision_id=None):
3125
"""Make a complete copy of the content in self into destination.
3127
This is a destructive operation! Do not use it on existing
3130
:param revision_id: Only copy the content needed to construct
3131
revision_id and its parents.
3134
self.target.set_make_working_trees(self.source.make_working_trees())
3135
except NotImplementedError:
3137
# but don't bother fetching if we have the needed data now.
3138
if (revision_id not in (None, _mod_revision.NULL_REVISION) and
3139
self.target.has_revision(revision_id)):
3141
self.target.fetch(self.source, revision_id=revision_id)
3144
class InterKnit1and2(InterKnitRepo):
3147
def _get_repo_format_to_test(self):
3151
def is_compatible(source, target):
3152
"""Be compatible with Knit1 source and Knit3 target"""
3154
from bzrlib.repofmt.knitrepo import (
3155
RepositoryFormatKnit1,
3156
RepositoryFormatKnit3,
3158
from bzrlib.repofmt.pack_repo import (
3159
RepositoryFormatKnitPack1,
3160
RepositoryFormatKnitPack3,
3161
RepositoryFormatKnitPack4,
3162
RepositoryFormatKnitPack5,
3163
RepositoryFormatKnitPack5RichRoot,
3164
RepositoryFormatKnitPack6,
3165
RepositoryFormatKnitPack6RichRoot,
3166
RepositoryFormatPackDevelopment2,
3167
RepositoryFormatPackDevelopment2Subtree,
3170
RepositoryFormatKnit1, # no rr, no subtree
3171
RepositoryFormatKnitPack1, # no rr, no subtree
3172
RepositoryFormatPackDevelopment2, # no rr, no subtree
3173
RepositoryFormatKnitPack5, # no rr, no subtree
3174
RepositoryFormatKnitPack6, # no rr, no subtree
3177
RepositoryFormatKnit3, # rr, subtree
3178
RepositoryFormatKnitPack3, # rr, subtree
3179
RepositoryFormatKnitPack4, # rr, no subtree
3180
RepositoryFormatKnitPack5RichRoot,# rr, no subtree
3181
RepositoryFormatKnitPack6RichRoot,# rr, no subtree
3182
RepositoryFormatPackDevelopment2Subtree, # rr, subtree
3184
for format in norichroot:
3185
if format.rich_root_data:
3186
raise AssertionError('Format %s is a rich-root format'
3187
' but is included in the non-rich-root list'
3189
for format in richroot:
3190
if not format.rich_root_data:
3191
raise AssertionError('Format %s is not a rich-root format'
3192
' but is included in the rich-root list'
3194
# TODO: One alternative is to just check format.rich_root_data,
3195
# instead of keeping membership lists. However, the formats
3196
# *also* have to use the same 'Knit' style of storage
3197
# (line-deltas, fulltexts, etc.)
3198
return (isinstance(source._format, norichroot) and
3199
isinstance(target._format, richroot))
3200
except AttributeError:
3204
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
3205
"""See InterRepository.fetch()."""
3206
from bzrlib.fetch import Knit1to2Fetcher
3207
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
3208
self.source, self.source._format, self.target,
3209
self.target._format)
3210
f = Knit1to2Fetcher(to_repository=self.target,
3211
from_repository=self.source,
3212
last_revision=revision_id,
3213
pb=pb, find_ghosts=find_ghosts)
3214
return f.count_copied, f.failed_revisions
3217
3114
class InterDifferingSerializer(InterKnitRepo):
3383
3283
return basis_id, basis_tree
3386
class InterOtherToRemote(InterRepository):
3387
"""An InterRepository that simply delegates to the 'real' InterRepository
3388
calculated for (source, target._real_repository).
3391
_walk_to_common_revisions_batch_size = 50
3393
def __init__(self, source, target):
3394
InterRepository.__init__(self, source, target)
3395
self._real_inter = None
3398
def is_compatible(source, target):
3399
if isinstance(target, remote.RemoteRepository):
3403
def _ensure_real_inter(self):
3404
if self._real_inter is None:
3405
self.target._ensure_real()
3406
real_target = self.target._real_repository
3407
self._real_inter = InterRepository.get(self.source, real_target)
3408
# Make _real_inter use the RemoteRepository for get_parent_map
3409
self._real_inter.target_get_graph = self.target.get_graph
3410
self._real_inter.target_get_parent_map = self.target.get_parent_map
3412
def copy_content(self, revision_id=None):
3413
self._ensure_real_inter()
3414
self._real_inter.copy_content(revision_id=revision_id)
3416
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
3417
self._ensure_real_inter()
3418
return self._real_inter.fetch(revision_id=revision_id, pb=pb,
3419
find_ghosts=find_ghosts)
3422
def _get_repo_format_to_test(self):
3426
class InterRemoteToOther(InterRepository):
3428
def __init__(self, source, target):
3429
InterRepository.__init__(self, source, target)
3430
self._real_inter = None
3433
def is_compatible(source, target):
3434
if not isinstance(source, remote.RemoteRepository):
3436
# Is source's model compatible with target's model?
3437
source._ensure_real()
3438
real_source = source._real_repository
3439
if isinstance(real_source, remote.RemoteRepository):
3440
raise NotImplementedError(
3441
"We don't support remote repos backed by remote repos yet.")
3442
return InterRepository._same_model(real_source, target)
3444
def _ensure_real_inter(self):
3445
if self._real_inter is None:
3446
self.source._ensure_real()
3447
real_source = self.source._real_repository
3448
self._real_inter = InterRepository.get(real_source, self.target)
3450
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
3451
self._ensure_real_inter()
3452
return self._real_inter.fetch(revision_id=revision_id, pb=pb,
3453
find_ghosts=find_ghosts)
3455
def copy_content(self, revision_id=None):
3456
self._ensure_real_inter()
3457
self._real_inter.copy_content(revision_id=revision_id)
3460
def _get_repo_format_to_test(self):
3465
class InterPackToRemotePack(InterPackRepo):
3466
"""A specialisation of InterPackRepo for a target that is a
3469
This will use the get_parent_map RPC rather than plain readvs, and also
3470
uses an RPC for autopacking.
3473
_walk_to_common_revisions_batch_size = 50
3476
def is_compatible(source, target):
3477
from bzrlib.repofmt.pack_repo import RepositoryFormatPack
3478
if isinstance(source._format, RepositoryFormatPack):
3479
if isinstance(target, remote.RemoteRepository):
3480
target._ensure_real()
3481
if isinstance(target._real_repository._format,
3482
RepositoryFormatPack):
3483
if InterRepository._same_model(source, target):
3487
def _autopack(self):
3488
self.target.autopack()
3491
def fetch(self, revision_id=None, pb=None, find_ghosts=False):
3492
"""See InterRepository.fetch()."""
3493
# Always fetch using the generic streaming fetch code, to allow
3494
# streaming fetching into remote servers.
3495
from bzrlib.fetch import RepoFetcher
3496
fetcher = RepoFetcher(self.target, self.source, revision_id,
3498
return fetcher.count_copied, fetcher.failed_revisions
3500
def _get_target_pack_collection(self):
3501
return self.target._real_repository._pack_collection
3504
def _get_repo_format_to_test(self):
3508
3286
InterRepository.register_optimiser(InterDifferingSerializer)
3509
3287
InterRepository.register_optimiser(InterSameDataRepository)
3510
3288
InterRepository.register_optimiser(InterWeaveRepo)
3511
3289
InterRepository.register_optimiser(InterKnitRepo)
3512
InterRepository.register_optimiser(InterModel1and2)
3513
InterRepository.register_optimiser(InterKnit1and2)
3514
3290
InterRepository.register_optimiser(InterPackRepo)
3515
InterRepository.register_optimiser(InterOtherToRemote)
3516
InterRepository.register_optimiser(InterRemoteToOther)
3517
InterRepository.register_optimiser(InterPackToRemotePack)
3520
3293
class CopyConverter(object):
3783
3557
self.target_repo.add_revision(revision_id, rev)
3785
3559
def finished(self):
3786
if self.target_repo._fetch_reconcile:
3560
if self.target_repo._format._fetch_reconcile:
3787
3561
self.target_repo.reconcile()
3564
class StreamSource(object):
3565
"""A source of a stream for fetching between repositories."""
3567
def __init__(self, from_repository, to_format):
3568
"""Create a StreamSource streaming from from_repository."""
3569
self.from_repository = from_repository
3570
self.to_format = to_format
3572
def delta_on_metadata(self):
3573
"""Return True if delta's are permitted on metadata streams.
3575
That is on revisions and signatures.
3577
src_serializer = self.from_repository._format._serializer
3578
target_serializer = self.to_format._serializer
3579
return (self.to_format._fetch_uses_deltas and
3580
src_serializer == target_serializer)
3582
def _fetch_revision_texts(self, revs):
3583
# fetch signatures first and then the revision texts
3584
# may need to be a InterRevisionStore call here.
3585
from_sf = self.from_repository.signatures
3586
# A missing signature is just skipped.
3587
keys = [(rev_id,) for rev_id in revs]
3588
signatures = versionedfile.filter_absent(from_sf.get_record_stream(
3590
self.to_format._fetch_order,
3591
not self.to_format._fetch_uses_deltas))
3592
# If a revision has a delta, this is actually expanded inside the
3593
# insert_record_stream code now, which is an alternate fix for
3595
from_rf = self.from_repository.revisions
3596
revisions = from_rf.get_record_stream(
3598
self.to_format._fetch_order,
3599
not self.delta_on_metadata())
3600
return [('signatures', signatures), ('revisions', revisions)]
3602
def _generate_root_texts(self, revs):
3603
"""This will be called by __fetch between fetching weave texts and
3604
fetching the inventory weave.
3606
Subclasses should override this if they need to generate root texts
3607
after fetching weave texts.
3609
if self._rich_root_upgrade():
3611
return bzrlib.fetch.Inter1and2Helper(
3612
self.from_repository).generate_root_texts(revs)
3616
def get_stream(self, search):
3618
revs = search.get_keys()
3619
graph = self.from_repository.get_graph()
3620
revs = list(graph.iter_topo_order(revs))
3621
data_to_fetch = self.from_repository.item_keys_introduced_by(revs)
3623
for knit_kind, file_id, revisions in data_to_fetch:
3624
if knit_kind != phase:
3626
# Make a new progress bar for this phase
3627
if knit_kind == "file":
3628
# Accumulate file texts
3629
text_keys.extend([(file_id, revision) for revision in
3631
elif knit_kind == "inventory":
3632
# Now copy the file texts.
3633
from_texts = self.from_repository.texts
3634
yield ('texts', from_texts.get_record_stream(
3635
text_keys, self.to_format._fetch_order,
3636
not self.to_format._fetch_uses_deltas))
3637
# Cause an error if a text occurs after we have done the
3640
# Before we process the inventory we generate the root
3641
# texts (if necessary) so that the inventories references
3643
for _ in self._generate_root_texts(revs):
3645
# NB: This currently reopens the inventory weave in source;
3646
# using a single stream interface instead would avoid this.
3647
from_weave = self.from_repository.inventories
3648
# we fetch only the referenced inventories because we do not
3649
# know for unselected inventories whether all their required
3650
# texts are present in the other repository - it could be
3652
yield ('inventories', from_weave.get_record_stream(
3653
[(rev_id,) for rev_id in revs],
3654
self.inventory_fetch_order(),
3655
not self.delta_on_metadata()))
3656
elif knit_kind == "signatures":
3657
# Nothing to do here; this will be taken care of when
3658
# _fetch_revision_texts happens.
3660
elif knit_kind == "revisions":
3661
for record in self._fetch_revision_texts(revs):
3664
raise AssertionError("Unknown knit kind %r" % knit_kind)
3666
def get_stream_for_missing_keys(self, missing_keys):
3667
# missing keys can only occur when we are byte copying and not
3668
# translating (because translation means we don't send
3669
# unreconstructable deltas ever).
3671
keys['texts'] = set()
3672
keys['revisions'] = set()
3673
keys['inventories'] = set()
3674
keys['signatures'] = set()
3675
for key in missing_keys:
3676
keys[key[0]].add(key[1:])
3677
if len(keys['revisions']):
3678
# If we allowed copying revisions at this point, we could end up
3679
# copying a revision without copying its required texts: a
3680
# violation of the requirements for repository integrity.
3681
raise AssertionError(
3682
'cannot copy revisions to fill in missing deltas %s' % (
3683
keys['revisions'],))
3684
for substream_kind, keys in keys.iteritems():
3685
vf = getattr(self.from_repository, substream_kind)
3686
# Ask for full texts always so that we don't need more round trips
3687
# after this stream.
3688
stream = vf.get_record_stream(keys,
3689
self.to_format._fetch_order, True)
3690
yield substream_kind, stream
3692
def inventory_fetch_order(self):
3693
if self._rich_root_upgrade():
3694
return 'topological'
3696
return self.to_format._fetch_order
3698
def _rich_root_upgrade(self):
3699
return (not self.from_repository._format.rich_root_data and
3700
self.to_format.rich_root_data)