1236
1236
stop_keys = result_parents.difference(start_set)
1237
1237
included_keys = start_set.intersection(result_parents)
1238
1238
start_set.difference_update(included_keys)
1239
recipe = (start_set, stop_keys, len(parents_map))
1239
recipe = ('manual', start_set, stop_keys, len(parents_map))
1240
1240
body = self._serialise_search_recipe(recipe)
1241
1241
path = self.bzrdir._path_for_remote_call(self._client)
1242
1242
for key in keys:
1305
1305
return self._real_repository.all_revision_ids()
1307
1307
@needs_read_lock
1308
def get_deltas_for_revisions(self, revisions):
1308
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
1309
1309
self._ensure_real()
1310
return self._real_repository.get_deltas_for_revisions(revisions)
1310
return self._real_repository.get_deltas_for_revisions(revisions,
1311
specific_fileids=specific_fileids)
1312
1313
@needs_read_lock
1313
def get_revision_delta(self, revision_id):
1314
def get_revision_delta(self, revision_id, specific_fileids=None):
1314
1315
self._ensure_real()
1315
return self._real_repository.get_revision_delta(revision_id)
1316
return self._real_repository.get_revision_delta(revision_id,
1317
specific_fileids=specific_fileids)
1317
1319
@needs_read_lock
1318
1320
def revision_trees(self, revision_ids):
1495
1497
:param recipe: A search recipe (start, stop, count).
1496
1498
:return: Serialised bytes.
1498
start_keys = ' '.join(recipe[0])
1499
stop_keys = ' '.join(recipe[1])
1500
count = str(recipe[2])
1500
start_keys = ' '.join(recipe[1])
1501
stop_keys = ' '.join(recipe[2])
1502
count = str(recipe[3])
1501
1503
return '\n'.join((start_keys, stop_keys, count))
1503
1505
def _serialise_search_result(self, search_result):
1584
1586
"""Stream data from a remote server."""
1586
1588
def get_stream(self, search):
1587
# streaming with fallback repositories is not well defined yet: The
1588
# remote repository cannot see the fallback repositories, and thus
1589
# cannot satisfy the entire search in the general case. Likewise the
1590
# fallback repositories cannot reify the search to determine what they
1591
# should send. It likely needs a return value in the stream listing the
1592
# edge of the search to resume from in fallback repositories.
1593
if self.from_repository._fallback_repositories:
1594
return repository.StreamSource.get_stream(self, search)
1595
repo = self.from_repository
1589
if (self.from_repository._fallback_repositories and
1590
self.to_format._fetch_order == 'topological'):
1591
return self._real_stream(self.from_repository, search)
1592
return self.missing_parents_chain(search, [self.from_repository] +
1593
self.from_repository._fallback_repositories)
1595
def _real_stream(self, repo, search):
1596
"""Get a stream for search from repo.
1598
This never called RemoteStreamSource.get_stream, and is a heler
1599
for RemoteStreamSource._get_stream to allow getting a stream
1600
reliably whether fallback back because of old servers or trying
1601
to stream from a non-RemoteRepository (which the stacked support
1604
source = repo._get_source(self.to_format)
1605
if isinstance(source, RemoteStreamSource):
1606
return repository.StreamSource.get_stream(source, search)
1607
return source.get_stream(search)
1609
def _get_stream(self, repo, search):
1610
"""Core worker to get a stream from repo for search.
1612
This is used by both get_stream and the stacking support logic. It
1613
deliberately gets a stream for repo which does not need to be
1614
self.from_repository. In the event that repo is not Remote, or
1615
cannot do a smart stream, a fallback is made to the generic
1616
repository._get_stream() interface, via self._real_stream.
1618
In the event of stacking, streams from _get_stream will not
1619
contain all the data for search - this is normal (see get_stream).
1621
:param repo: A repository.
1622
:param search: A search.
1624
# Fallbacks may be non-smart
1625
if not isinstance(repo, RemoteRepository):
1626
return self._real_stream(repo, search)
1596
1627
client = repo._client
1597
1628
medium = client._medium
1598
1629
if medium._is_remote_before((1, 13)):
1599
# No possible way this can work.
1600
return repository.StreamSource.get_stream(self, search)
1630
# streaming was added in 1.13
1631
return self._real_stream(repo, search)
1601
1632
path = repo.bzrdir._path_for_remote_call(client)
1603
1634
search_bytes = repo._serialise_search_result(search)
1607
1638
response_tuple, response_handler = response
1608
1639
except errors.UnknownSmartMethod:
1609
1640
medium._remember_remote_is_before((1,13))
1610
return repository.StreamSource.get_stream(self, search)
1641
return self._real_stream(repo, search)
1611
1642
if response_tuple[0] != 'ok':
1612
1643
raise errors.UnexpectedSmartServerResponse(response_tuple)
1613
1644
byte_stream = response_handler.read_streamed_body()
1618
1649
src_format.network_name(), repo._format.network_name()))
1652
def missing_parents_chain(self, search, sources):
1653
"""Chain multiple streams together to handle stacking.
1655
:param search: The overall search to satisfy with streams.
1656
:param sources: A list of Repository objects to query.
1658
self.serialiser = self.to_format._serializer
1659
self.seen_revs = set()
1660
self.referenced_revs = set()
1661
# If there are heads in the search, or the key count is > 0, we are not
1663
while not search.is_empty() and len(sources) > 1:
1664
source = sources.pop(0)
1665
stream = self._get_stream(source, search)
1666
for kind, substream in stream:
1667
if kind != 'revisions':
1668
yield kind, substream
1670
yield kind, self.missing_parents_rev_handler(substream)
1671
search = search.refine(self.seen_revs, self.referenced_revs)
1672
self.seen_revs = set()
1673
self.referenced_revs = set()
1674
if not search.is_empty():
1675
for kind, stream in self._get_stream(sources[0], search):
1678
def missing_parents_rev_handler(self, substream):
1679
for content in substream:
1680
revision_bytes = content.get_bytes_as('fulltext')
1681
revision = self.serialiser.read_revision_from_string(revision_bytes)
1682
self.seen_revs.add(content.key[-1])
1683
self.referenced_revs.update(revision.parent_ids)
1622
1687
class RemoteBranchLockableFiles(LockableFiles):
1623
1688
"""A 'LockableFiles' implementation that talks to a smart server.