Merge lp:~abentley/bzr/fix-shelf into lp:~bzr/bzr/trunk-old

Proposed by Aaron Bentley
Status: Merged
Merged at revision: not available
Proposed branch: lp:~abentley/bzr/fix-shelf
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: None lines
To merge this branch: bzr merge lp:~abentley/bzr/fix-shelf
Reviewer Review Type Date Requested Status
Andrew Bennetts Approve
Review via email: mp+7699@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi all,

This fixes a bug in the ContainerPushParser, which indrectly causes
unshelve to crash when unshelving zero-length files.

The problem is that ContainerPushParser uses self._buffer as an
indicator of progress. It assumes that if self._buffer did not change,
no progress could be made in parsing records. But in the case of a
zero-length record, _state_expecting_body will move on to the next state
 handler, without changing the length of self._buffer. This is clearly
progress.

The result of this bug is that the parser stops at the first zero-length
record, which causes TreeTransform.deserialize to produce an incomplete
TreeTransform, which causes PreviewTree.stored_kind to raise an exception.

This patch simply augments test for progress by requiring that
self._buffer have a different length, OR that the state_handler be changed.

I am inclined to think that it would be more robust to have a flag
indicating whether progress occurred, or even to raise an exception when
progress ceases.

Aaron
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAko8O6sACgkQ0F+nu1YWqI1LkQCgh6KV6lZd0ps9wBS2eBa+R743
BH0An25+SE9z1JcxgkZYK3rhtUyot9Dz
=WEdZ
-----END PGP SIGNATURE-----

Revision history for this message
Andrew Bennetts (spiv) wrote :

The code and test makes sense. Thanks for fixing my code :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/pack.py'
2--- bzrlib/pack.py 2009-04-04 02:50:01 +0000
3+++ bzrlib/pack.py 2009-06-20 01:17:38 +0000
4@@ -406,8 +406,11 @@
5 # the buffer.
6 last_buffer_length = None
7 cur_buffer_length = len(self._buffer)
8- while cur_buffer_length != last_buffer_length:
9+ last_state_handler = None
10+ while (cur_buffer_length != last_buffer_length
11+ or last_state_handler != self._state_handler):
12 last_buffer_length = cur_buffer_length
13+ last_state_handler = self._state_handler
14 self._state_handler()
15 cur_buffer_length = len(self._buffer)
16
17
18=== modified file 'bzrlib/tests/test_pack.py'
19--- bzrlib/tests/test_pack.py 2009-03-23 14:59:43 +0000
20+++ bzrlib/tests/test_pack.py 2009-06-20 01:17:38 +0000
21@@ -610,6 +610,19 @@
22 [([('name1',)], 'body1'), ([('name2',)], 'body2')],
23 parser.read_pending_records())
24
25+ def test_multiple_empty_records_at_once(self):
26+ """If multiple empty records worth of data are fed to the parser in one
27+ string, the parser will correctly parse all the records.
28+
29+ (A naive implementation might stop after parsing the first empty
30+ record, because the buffer size had not changed.)
31+ """
32+ parser = self.make_parser_expecting_record_type()
33+ parser.accept_bytes("B0\nname1\n\nB0\nname2\n\n")
34+ self.assertEqual(
35+ [([('name1',)], ''), ([('name2',)], '')],
36+ parser.read_pending_records())
37+
38
39 class TestContainerPushParserBytesParsing(PushParserTestCase):
40 """Tests for reading Bytes records with ContainerPushParser.