1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-01 18:30:59 +01:00

Fix loop in svnserve workflow for large binaries

Summary: If you push a large binary and the data crosses multiple data frames, we can end up in a loop in the parser.

Test Plan:
After this change, I was able to push a 95MB binary in 7s, which seems reasonable:

  >>> orbital ~/repos/INIS $ svn st
  A       large2.bin
  >>> orbital ~/repos/INIS $ ls -alh
  total 390648
  drwxr-xr-x   6 epriestley  admin   204B Dec 18 17:14 .
  drwxr-xr-x  98 epriestley  admin   3.3K Dec 16 11:19 ..
  drwxr-xr-x   7 epriestley  admin   238B Dec 18 17:14 .svn
  -rw-r--r--   1 epriestley  admin    80B Dec 18 15:07 README
  -rw-r--r--   1 epriestley  admin    95M Dec 18 16:53 large.bin
  -rw-r--r--   1 epriestley  admin    95M Dec 18 17:14 large2.bin
  >>> orbital ~/repos/INIS $ time svn commit -m 'another large binary'
  Adding  (bin)  large2.bin
  Transmitting file data .
  Committed revision 25.

  real	0m7.215s
  user	0m5.327s
  sys	0m0.407s
  >>> orbital ~/repos/INIS $

There may be room to improve this by using `PhutilRope`.

Reviewers: wrotte, btrahan, wotte

Reviewed By: wotte

CC: aran

Differential Revision: https://secure.phabricator.com/D7798
This commit is contained in:
epriestley 2013-12-18 17:48:29 -08:00
parent 92bc76aae0
commit f37832aed7
2 changed files with 29 additions and 0 deletions

View file

@ -75,6 +75,10 @@ final class DiffusionSubversionWireProtocol extends Phobject {
}
} else if ($this->state == 'bytes') {
$new_data = substr($this->buffer, 0, $this->expectBytes);
if (!strlen($new_data)) {
// No more bytes available yet, wait for more data.
break;
}
$this->buffer = substr($this->buffer, strlen($new_data));
$this->expectBytes -= strlen($new_data);

View file

@ -61,6 +61,31 @@ final class DiffusionSubversionWireProtocolTestCase
));
}
public function testSubversionWireProtocolPartialFrame() {
$proto = new DiffusionSubversionWireProtocol();
// This is primarily a test that we don't hang when we write() a frame
// which straddles a string boundary.
$msg1 = $proto->writeData('( duck 5:qu');
$msg2 = $proto->writeData('ack ) ');
$this->assertEqual(array(), ipull($msg1, 'structure'));
$this->assertEqual(
array(
array(
array(
'type' => 'word',
'value' => 'duck',
),
array(
'type'=> 'string',
'value' => 'quack',
),
),
),
ipull($msg2, 'structure'));
}
private function assertSameSubversionMessages($string, array $structs) {
$proto = new DiffusionSubversionWireProtocol();