Rev 6318: (jelmer) Add HPSS call for ``Repository.iter_files_bytes``. (Jelmer Vernooij) in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Nov 28 16:29:49 UTC 2011
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6318 [merge]
revision-id: pqm at pqm.ubuntu.com-20111128162949-cx0obntgfj3rzhgr
parent: pqm at pqm.ubuntu.com-20111128160445-5ndgnqjd0vggze3d
parent: jelmer at samba.org-20111128155939-709ll9ta5aqduig0
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2011-11-28 16:29:49 +0000
message:
(jelmer) Add HPSS call for ``Repository.iter_files_bytes``. (Jelmer Vernooij)
modified:
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/revisiontree.py revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
bzrlib/smart/repository.py repository.py-20061128022038-vr5wy5bubyb8xttk-1
bzrlib/smart/request.py request.py-20061108095550-gunadhxmzkdjfeek-1
bzrlib/tests/blackbox/test_cat.py test_cat.py-20051201162916-f0937e4e19ea24b3
bzrlib/tests/blackbox/test_export.py test_export.py-20051229024010-e6c26658e460fb1c
bzrlib/tests/per_bzrdir/test_bzrdir.py test_bzrdir.py-20100829143338-2uachgod1c3liktl-1
bzrlib/tests/per_repository_vf/test_check_reconcile.py test_broken.py-20070928125406-62236394w0jpbpd6-2
bzrlib/tests/test_remote.py test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
bzrlib/tests/test_smart.py test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
bzrlib/vf_repository.py vf_repository.py-20110502151858-yh9nnoxpokg86unk-1
doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py 2011-11-28 14:18:56 +0000
+++ b/bzrlib/remote.py 2011-11-28 15:59:39 +0000
@@ -29,6 +29,7 @@
graph,
lock,
lockdir,
+ osutils,
registry,
repository as _mod_repository,
revision as _mod_revision,
@@ -1784,8 +1785,7 @@
@needs_read_lock
def get_inventory(self, revision_id):
- self._ensure_real()
- return self._real_repository.get_inventory(revision_id)
+ return list(self.iter_inventories([revision_id]))[0]
def iter_inventories(self, revision_ids, ordering=None):
self._ensure_real()
@@ -1918,11 +1918,80 @@
return self._real_repository._get_versioned_file_checker(
revisions, revision_versions_cache)
+ def _iter_files_bytes_rpc(self, desired_files, absent):
+ path = self.bzrdir._path_for_remote_call(self._client)
+ lines = []
+ identifiers = []
+ for (file_id, revid, identifier) in desired_files:
+ lines.append("%s\0%s" % (
+ osutils.safe_file_id(file_id),
+ osutils.safe_revision_id(revid)))
+ identifiers.append(identifier)
+ (response_tuple, response_handler) = (
+ self._call_with_body_bytes_expecting_body(
+ "Repository.iter_files_bytes", (path, ), "\n".join(lines)))
+ if response_tuple != ('ok', ):
+ response_handler.cancel_read_body()
+ raise errors.UnexpectedSmartServerResponse(response_tuple)
+ byte_stream = response_handler.read_streamed_body()
+ def decompress_stream(start, byte_stream, unused):
+ decompressor = zlib.decompressobj()
+ yield decompressor.decompress(start)
+ while decompressor.unused_data == "":
+ try:
+ data = byte_stream.next()
+ except StopIteration:
+ break
+ yield decompressor.decompress(data)
+ yield decompressor.flush()
+ unused.append(decompressor.unused_data)
+ unused = ""
+ while True:
+ while not "\n" in unused:
+ unused += byte_stream.next()
+ header, rest = unused.split("\n", 1)
+ args = header.split("\0")
+ if args[0] == "absent":
+ absent[identifiers[int(args[3])]] = (args[1], args[2])
+ unused = rest
+ continue
+ elif args[0] == "ok":
+ idx = int(args[1])
+ else:
+ raise errors.UnexpectedSmartServerResponse(args)
+ unused_chunks = []
+ yield (identifiers[idx],
+ decompress_stream(rest, byte_stream, unused_chunks))
+ unused = "".join(unused_chunks)
+
def iter_files_bytes(self, desired_files):
"""See Repository.iter_file_bytes.
"""
- self._ensure_real()
- return self._real_repository.iter_files_bytes(desired_files)
+ try:
+ absent = {}
+ for (identifier, bytes_iterator) in self._iter_files_bytes_rpc(
+ desired_files, absent):
+ yield identifier, bytes_iterator
+ for fallback in self._fallback_repositories:
+ if not absent:
+ break
+ desired_files = [(key[0], key[1], identifier) for
+ (identifier, key) in absent.iteritems()]
+ for (identifier, bytes_iterator) in fallback.iter_files_bytes(desired_files):
+ del absent[identifier]
+ yield identifier, bytes_iterator
+ if absent:
+ # There may be more missing items, but raise an exception
+ # for just one.
+ missing_identifier = absent.keys()[0]
+ missing_key = absent[missing_identifier]
+ raise errors.RevisionNotPresent(revision_id=missing_key[1],
+ file_id=missing_key[0])
+ except errors.UnknownSmartMethod:
+ self._ensure_real()
+ for (identifier, bytes_iterator) in (
+ self._real_repository.iter_files_bytes(desired_files)):
+ yield identifier, bytes_iterator
def get_cached_parent_map(self, revision_ids):
"""See bzrlib.CachingParentsProvider.get_cached_parent_map"""
@@ -2111,8 +2180,9 @@
@needs_read_lock
def revision_trees(self, revision_ids):
- self._ensure_real()
- return self._real_repository.revision_trees(revision_ids)
+ inventories = self.iter_inventories(revision_ids)
+ for inv in inventories:
+ yield InventoryRevisionTree(self, inv, inv.revision_id)
@needs_read_lock
def get_revision_reconcile(self, revision_id):
@@ -2137,7 +2207,6 @@
def _copy_repository_tarball(self, to_bzrdir, revision_id=None):
# get a tarball of the remote repository, and copy from that into the
# destination
- from bzrlib import osutils
import tarfile
# TODO: Maybe a progress bar while streaming the tarball?
note(gettext("Copying repository content as tarball..."))
@@ -2197,9 +2266,6 @@
def revisions(self):
"""Decorate the real repository for now.
- In the short term this should become a real object to intercept graph
- lookups.
-
In the long term a full blown network facility is needed.
"""
self._ensure_real()
@@ -2336,12 +2402,14 @@
return self._real_repository.add_signature_text(
revision_id, signature)
path = self.bzrdir._path_for_remote_call(self._client)
- response, response_handler = self._call_with_body_bytes(
- 'Repository.add_signature_text', (path, revision_id),
- signature)
+ response, handler = self._call_with_body_bytes_expecting_body(
+ 'Repository.add_signature_text', (path, self._lock_token,
+ revision_id) + tuple(self._write_group_tokens), signature)
+ handler.cancel_read_body()
self.refresh_data()
if response[0] != 'ok':
raise errors.UnexpectedSmartServerResponse(response)
+ self._write_group_tokens = response[1:]
def has_signature_for_revision_id(self, revision_id):
path = self.bzrdir._path_for_remote_call(self._client)
@@ -3855,6 +3923,13 @@
lambda err, find, get_path: errors.ReadError(get_path()))
error_translators.register('NoSuchFile',
lambda err, find, get_path: errors.NoSuchFile(get_path()))
+error_translators.register('UnsuspendableWriteGroup',
+ lambda err, find, get_path: errors.UnsuspendableWriteGroup(
+ repository=find('repository')))
+error_translators.register('UnresumableWriteGroup',
+ lambda err, find, get_path: errors.UnresumableWriteGroup(
+ repository=find('repository'), write_groups=err.error_args[0],
+ reason=err.error_args[1]))
no_context_error_translators.register('IncompatibleRepositories',
lambda err: errors.IncompatibleRepositories(
err.error_args[0], err.error_args[1], err.error_args[2]))
@@ -3905,14 +3980,9 @@
no_context_error_translators.register('MemoryError',
lambda err: errors.BzrError("remote server out of memory\n"
"Retry non-remotely, or contact the server admin for details."))
+no_context_error_translators.register('RevisionNotPresent',
+ lambda err: errors.RevisionNotPresent(err.error_args[0], err.error_args[1]))
no_context_error_translators.register('BzrCheckError',
lambda err: errors.BzrCheckError(msg=err.error_args[0]))
-error_translators.register('UnsuspendableWriteGroup',
- lambda err, find, get_path: errors.UnsuspendableWriteGroup(
- repository=find('repository')))
-error_translators.register('UnresumableWriteGroup',
- lambda err, find, get_path: errors.UnresumableWriteGroup(
- repository=find('repository'), write_groups=err.error_args[0],
- reason=err.error_args[1]))
=== modified file 'bzrlib/revisiontree.py'
--- a/bzrlib/revisiontree.py 2011-08-29 19:06:57 +0000
+++ b/bzrlib/revisiontree.py 2011-11-21 17:07:19 +0000
@@ -65,8 +65,9 @@
raise NotImplementedError(self.get_file_revision)
def get_file_text(self, file_id, path=None):
- _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
- return ''.join(content)
+ for (identifier, content) in self.iter_files_bytes([(file_id, None)]):
+ ret = "".join(content)
+ return ret
def get_file(self, file_id, path=None):
return StringIO(self.get_file_text(file_id))
@@ -215,14 +216,14 @@
def iter_files_bytes(self, desired_files):
"""See Tree.iter_files_bytes.
- This version is implemented on top of Repository.extract_files_bytes"""
+ This version is implemented on top of Repository.iter_files_bytes"""
repo_desired_files = [(f, self.get_file_revision(f), i)
for f, i in desired_files]
try:
for result in self._repository.iter_files_bytes(repo_desired_files):
yield result
except errors.RevisionNotPresent, e:
- raise errors.NoSuchFile(e.revision_id)
+ raise errors.NoSuchFile(e.file_id)
def annotate_iter(self, file_id,
default_revision=revision.CURRENT_REVISION):
=== modified file 'bzrlib/smart/repository.py'
--- a/bzrlib/smart/repository.py 2011-11-28 14:18:56 +0000
+++ b/bzrlib/smart/repository.py 2011-11-28 15:59:39 +0000
@@ -963,18 +963,18 @@
New in 2.5.
"""
- def do_repository_request(self, repository, lock_token, write_group_tokens,
- revision_id):
+ def do_repository_request(self, repository, lock_token, revision_id,
+ *write_group_tokens):
"""Add a revision signature text.
:param repository: Repository to operate on
:param lock_token: Lock token
+ :param revision_id: Revision for which to add signature
:param write_group_tokens: Write group tokens
- :param revision_id: Revision for which to add signature
"""
self._lock_token = lock_token
+ self._revision_id = revision_id
self._write_group_tokens = write_group_tokens
- self._revision_id = revision_id
return None
def do_body(self, body_bytes):
@@ -988,12 +988,14 @@
try:
self._repository.resume_write_group(self._write_group_tokens)
try:
- self._repository.add_signature_text(self._revision_id, body_bytes)
+ self._repository.add_signature_text(self._revision_id,
+ body_bytes)
finally:
new_write_group_tokens = self._repository.suspend_write_group()
finally:
self._repository.unlock()
- return SuccessfulSmartServerResponse(('ok', ) + tuple(new_write_group_tokens))
+ return SuccessfulSmartServerResponse(
+ ('ok', ) + tuple(new_write_group_tokens))
class SmartServerRepositoryStartWriteGroup(SmartServerRepositoryRequest):
@@ -1126,6 +1128,63 @@
return SuccessfulSmartServerResponse(("ok", ), )
+class SmartServerRepositoryIterFilesBytes(SmartServerRepositoryRequest):
+ """Iterate over the contents of files.
+
+ The client sends a list of desired files to stream, one
+ per line, and as tuples of file id and revision, separated by
+ \0.
+
+ The server replies with a stream. Each entry is preceded by a header,
+ which can either be:
+
+ * "ok\x00IDX\n" where IDX is the index of the entry in the desired files
+ list sent by the client. This header is followed by the contents of
+ the file, bzip2-compressed.
+ * "absent\x00FILEID\x00REVISION\x00IDX" to indicate a text is missing.
+ The client can then raise an appropriate RevisionNotPresent error
+ or check its fallback repositories.
+
+ New in 2.5.
+ """
+
+ def body_stream(self, repository, desired_files):
+ self._repository.lock_read()
+ try:
+ text_keys = {}
+ for i, key in enumerate(desired_files):
+ text_keys[key] = i
+ for record in repository.texts.get_record_stream(text_keys,
+ 'unordered', True):
+ identifier = text_keys[record.key]
+ if record.storage_kind == 'absent':
+ yield "absent\0%s\0%s\0%d\n" % (record.key[0],
+ record.key[1], identifier)
+ # FIXME: Way to abort early?
+ continue
+ yield "ok\0%d\n" % identifier
+ compressor = zlib.compressobj()
+ for bytes in record.get_bytes_as('chunked'):
+ data = compressor.compress(bytes)
+ if data:
+ yield data
+ data = compressor.flush()
+ if data:
+ yield data
+ finally:
+ self._repository.unlock()
+
+ def do_body(self, body_bytes):
+ desired_files = [
+ tuple(l.split("\0")) for l in body_bytes.splitlines()]
+ return SuccessfulSmartServerResponse(('ok', ),
+ body_stream=self.body_stream(self._repository, desired_files))
+
+ def do_repository_request(self, repository):
+ # Signal that we want a body
+ return None
+
+
class SmartServerRepositoryIterRevisions(SmartServerRepositoryRequest):
"""Stream a list of revisions.
=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py 2011-11-28 14:18:56 +0000
+++ b/bzrlib/smart/request.py 2011-11-28 15:59:39 +0000
@@ -415,6 +415,8 @@
elif isinstance(err, errors.ShortReadvError):
return ('ShortReadvError', err.path, str(err.offset), str(err.length),
str(err.actual))
+ elif isinstance(err, errors.RevisionNotPresent):
+ return ('RevisionNotPresent', err.revision_id, err.file_id)
elif isinstance(err, errors.UnstackableRepositoryFormat):
return (('UnstackableRepositoryFormat', str(err.format), err.url))
elif isinstance(err, errors.UnstackableBranchFormat):
@@ -658,6 +660,9 @@
request_handlers.register_lazy(
'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
request_handlers.register_lazy(
+ 'Repository.iter_files_bytes', 'bzrlib.smart.repository',
+ 'SmartServerRepositoryIterFilesBytes')
+request_handlers.register_lazy(
'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
request_handlers.register_lazy(
'Repository.make_working_trees', 'bzrlib.smart.repository', 'SmartServerRepositoryMakeWorkingTrees')
=== modified file 'bzrlib/tests/blackbox/test_cat.py'
--- a/bzrlib/tests/blackbox/test_cat.py 2011-11-22 23:15:35 +0000
+++ b/bzrlib/tests/blackbox/test_cat.py 2011-11-23 12:02:26 +0000
@@ -238,4 +238,4 @@
# being too low. If rpc_count increases, more network roundtrips have
# become necessary for this use case. Please do not adjust this number
# upwards without agreement from bzr's network support maintainers.
- self.assertLength(17, self.hpss_calls)
+ self.assertLength(16, self.hpss_calls)
=== modified file 'bzrlib/tests/blackbox/test_export.py'
--- a/bzrlib/tests/blackbox/test_export.py 2011-11-22 23:34:54 +0000
+++ b/bzrlib/tests/blackbox/test_export.py 2011-11-23 12:02:26 +0000
@@ -430,4 +430,4 @@
# being too low. If rpc_count increases, more network roundtrips have
# become necessary for this use case. Please do not adjust this number
# upwards without agreement from bzr's network support maintainers.
- self.assertLength(17, self.hpss_calls)
+ self.assertLength(16, self.hpss_calls)
=== modified file 'bzrlib/tests/per_bzrdir/test_bzrdir.py'
--- a/bzrlib/tests/per_bzrdir/test_bzrdir.py 2011-11-04 16:32:00 +0000
+++ b/bzrlib/tests/per_bzrdir/test_bzrdir.py 2011-11-21 18:59:51 +0000
@@ -162,8 +162,12 @@
for file_id, revision_id in text_index.iterkeys():
desired_files.append(
(file_id, revision_id, (file_id, revision_id)))
- left_texts = list(left_repo.iter_files_bytes(desired_files))
- right_texts = list(right_repo.iter_files_bytes(desired_files))
+ left_texts = [(identifier, "".join(bytes_iterator)) for
+ (identifier, bytes_iterator) in
+ left_repo.iter_files_bytes(desired_files)]
+ right_texts = [(identifier, "".join(bytes_iterator)) for
+ (identifier, bytes_iterator) in
+ right_repo.iter_files_bytes(desired_files)]
left_texts.sort()
right_texts.sort()
self.assertEqual(left_texts, right_texts)
=== modified file 'bzrlib/tests/per_repository_vf/test_check_reconcile.py'
--- a/bzrlib/tests/per_repository_vf/test_check_reconcile.py 2011-05-11 14:26:41 +0000
+++ b/bzrlib/tests/per_repository_vf/test_check_reconcile.py 2011-11-28 13:33:08 +0000
@@ -461,7 +461,8 @@
# make rev1b: A well-formed revision, containing 'a-file'
# rev1b of a-file has the exact same contents as rev1a.
- file_contents = repo.revision_tree('rev1a').get_file_text('a-file-id')
+ file_contents = repo.texts.get_record_stream([('a-file-id', 'rev1a')],
+ "unordered", False).next().get_bytes_as('fulltext')
inv = self.make_one_file_inventory(
repo, 'rev1b', [], root_revision='rev1b',
file_contents=file_contents)
=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py 2011-11-28 14:18:56 +0000
+++ b/bzrlib/tests/test_remote.py 2011-11-28 15:59:39 +0000
@@ -2413,14 +2413,26 @@
def test_add_signature_text(self):
transport_path = 'quack'
repo, client = self.setup_fake_client_and_repository(transport_path)
- client.add_success_response('ok')
+ client.add_expected_call(
+ 'Repository.lock_write', ('quack/', ''),
+ 'success', ('ok', 'a token'))
+ client.add_expected_call(
+ 'Repository.start_write_group', ('quack/', 'a token'),
+ 'success', ('ok', ('token1', )))
+ client.add_expected_call(
+ 'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
+ 'token1'),
+ 'success', ('ok', ), None)
+ repo.lock_write()
+ repo.start_write_group()
self.assertIs(None,
repo.add_signature_text("rev1", "every bloody emperor"))
self.assertEqual(
- [('call_with_body_bytes',
- 'Repository.add_signature_text', ('quack/', 'rev1', ),
- 'every bloody emperor')],
- client._calls)
+ ('call_with_body_bytes_expecting_body',
+ 'Repository.add_signature_text',
+ ('quack/', 'a token', 'rev1', 'token1'),
+ 'every bloody emperor'),
+ client._calls[-1])
class TestRepositoryGetParentMap(TestRemoteRepository):
@@ -2987,7 +2999,7 @@
'success', ('ok', 'a token'))
client.add_expected_call(
'Repository.start_write_group', ('quack/', 'a token'),
- 'success', ('ok', 'token1'))
+ 'success', ('ok', ('token1', )))
repo.lock_write()
repo.start_write_group()
@@ -3126,6 +3138,33 @@
self.assertEqual([], client._calls)
+class TestRepositoryIterFilesBytes(TestRemoteRepository):
+ """Test Repository.iter_file_bytes."""
+
+ def test_single(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.iter_files_bytes', ('quack/', ),
+ 'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
+ for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
+ "somerev", "myid")]):
+ self.assertEquals("myid", identifier)
+ self.assertEquals("".join(byte_stream), "mydata" * 10)
+
+ def test_missing(self):
+ transport_path = 'quack'
+ repo, client = self.setup_fake_client_and_repository(transport_path)
+ client.add_expected_call(
+ 'Repository.iter_files_bytes',
+ ('quack/', ),
+ 'error', ('RevisionNotPresent', 'somefile', 'somerev'),
+ iter(["absent\0somefile\0somerev\n"]))
+ self.assertRaises(errors.RevisionNotPresent, list,
+ repo.iter_files_bytes(
+ [("somefile", "somerev", "myid")]))
+
+
class TestRepositoryInsertStreamBase(TestRemoteRepository):
"""Base class for Repository.insert_stream and .insert_stream_1.19
tests.
=== modified file 'bzrlib/tests/test_smart.py'
--- a/bzrlib/tests/test_smart.py 2011-11-28 14:18:56 +0000
+++ b/bzrlib/tests/test_smart.py 2011-11-28 15:59:39 +0000
@@ -1541,7 +1541,7 @@
tree.branch.repository.start_write_group()
write_group_tokens = tree.branch.repository.suspend_write_group()
self.assertEqual(None, request.execute('', write_token,
- write_group_tokens, 'rev1'))
+ 'rev1', *write_group_tokens))
response = request.do_body('somesignature')
self.assertTrue(response.is_successful())
self.assertEqual(response.args[0], 'ok')
@@ -1849,6 +1849,36 @@
request.execute('', rev_id_utf8))
+class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
+
+ def test_single(self):
+ backing = self.get_transport()
+ request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
+ t = self.make_branch_and_tree('.')
+ self.addCleanup(t.lock_write().unlock)
+ self.build_tree_contents([("file", "somecontents")])
+ t.add(["file"], ["thefileid"])
+ t.commit(rev_id='somerev', message="add file")
+ self.assertIs(None, request.execute(''))
+ response = request.do_body("thefileid\0somerev\n")
+ self.assertTrue(response.is_successful())
+ self.assertEquals(response.args, ("ok", ))
+ self.assertEquals("".join(response.body_stream),
+ "ok\x000\n" + zlib.compress("somecontents"))
+
+ def test_missing(self):
+ backing = self.get_transport()
+ request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
+ t = self.make_branch_and_tree('.')
+ self.addCleanup(t.lock_write().unlock)
+ self.assertIs(None, request.execute(''))
+ response = request.do_body("thefileid\0revision\n")
+ self.assertTrue(response.is_successful())
+ self.assertEquals(response.args, ("ok", ))
+ self.assertEquals("".join(response.body_stream),
+ "absent\x00thefileid\x00revision\x000\n")
+
+
class TestSmartServerRequestHasSignatureForRevisionId(
tests.TestCaseWithMemoryTransport):
@@ -2472,6 +2502,8 @@
smart_repo.SmartServerRepositoryInsertStreamLocked)
self.assertHandlerEqual('Repository.is_shared',
smart_repo.SmartServerRepositoryIsShared)
+ self.assertHandlerEqual('Repository.iter_files_bytes',
+ smart_repo.SmartServerRepositoryIterFilesBytes)
self.assertHandlerEqual('Repository.lock_write',
smart_repo.SmartServerRepositoryLockWrite)
self.assertHandlerEqual('Repository.make_working_trees',
=== modified file 'bzrlib/vf_repository.py'
--- a/bzrlib/vf_repository.py 2011-10-17 08:45:09 +0000
+++ b/bzrlib/vf_repository.py 2011-11-20 02:16:25 +0000
@@ -1516,7 +1516,7 @@
text_keys[(file_id, revision_id)] = callable_data
for record in self.texts.get_record_stream(text_keys, 'unordered', True):
if record.storage_kind == 'absent':
- raise errors.RevisionNotPresent(record.key, self)
+ raise errors.RevisionNotPresent(record.key[1], record.key[0])
yield text_keys[record.key], record.get_bytes_as('chunked')
def _generate_text_key_index(self, text_key_references=None,
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt 2011-11-28 14:18:56 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt 2011-11-28 15:59:39 +0000
@@ -53,6 +53,11 @@
* Add HPSS call for looking up revision numbers from revision ids on
remote repositories. (Jelmer Vernooij, #640253)
+* Add HPSS call for retrieving file contents from remote repositories.
+ Should improve performance for lightweight checkouts and exports of
+ from remote repositories. (Jelmer Vernooij, #368717, #762330,
+ #608640)
+
* Cope with missing revision ids being specified to
``Repository.gather_stats`` HPSS call. (Jelmer Vernooij, #411290)
More information about the bazaar-commits
mailing list