1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-20 20:40:56 +01:00

Truncate object fields in Herald transcripts

Summary:
A few users have hit cases where Herald transcripts of large commits exceed the MySQL packet limit, because one of the fields in the transcript is an enomrous textual diff.

There's no value in saving these huge amounts of data. Transcripts are useful for understanding the action of Herald rules, but can be reconstructed later. Instead of saving all of the data, limit each field to 4KB of data.

For strings, we just truncate at 4KB. For arrays, we truncate after 4KB of values.

Test Plan: Ran unit tests. Artificially decreased limit and ran transcripts, saw them truncate properly.

Reviewers: btrahan

Reviewed By: btrahan

CC: frgtn, aran

Differential Revision: https://secure.phabricator.com/D7783
This commit is contained in:
epriestley 2013-12-18 11:59:53 -08:00
parent b0f7e7a6af
commit 181bfffaa1
3 changed files with 79 additions and 0 deletions

View file

@ -779,6 +779,7 @@ phutil_register_library_map(array(
'HeraldTranscriptController' => 'applications/herald/controller/HeraldTranscriptController.php',
'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php',
'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php',
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
'Javelin' => 'infrastructure/javelin/Javelin.php',
'JavelinReactorExample' => 'applications/uiexample/examples/JavelinReactorExample.php',
'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php',
@ -3211,6 +3212,7 @@ phutil_register_library_map(array(
'HeraldTranscriptController' => 'HeraldController',
'HeraldTranscriptListController' => 'HeraldController',
'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
'JavelinReactorExample' => 'PhabricatorUIExample',
'JavelinUIExample' => 'PhabricatorUIExample',
'JavelinViewExample' => 'PhabricatorUIExample',

View file

@ -0,0 +1,47 @@
<?php
final class HeraldTranscriptTestCase extends PhabricatorTestCase {
public function testTranscriptTruncation() {
$long_string = str_repeat('x', 1024 * 1024);
$short_string = str_repeat('x', 4096)."\n<...>";
$long_array = array(
'a' => $long_string,
'b' => $long_string,
);
$mixed_array = array(
'a' => 'abc',
'b' => 'def',
'c' => $long_string,
);
$fields = array(
'ls' => $long_string,
'la' => $long_array,
'ma' => $mixed_array,
);
$truncated_fields = id(new HeraldObjectTranscript())
->setFields($fields)
->getFields();
$this->assertEqual($short_string, $truncated_fields['ls']);
$this->assertEqual(
array('a', '<...>'),
array_keys($truncated_fields['la']));
$this->assertEqual(
$short_string.'!<...>',
implode('!', $truncated_fields['la']));
$this->assertEqual(
array('a', 'b', 'c'),
array_keys($truncated_fields['ma']));
$this->assertEqual(
'abc!def!'.substr($short_string, 6),
implode('!', $truncated_fields['ma']));
}
}

View file

@ -35,6 +35,10 @@ final class HeraldObjectTranscript {
}
public function setFields(array $fields) {
foreach ($fields as $key => $value) {
$fields[$key] = self::truncateValue($value, 4096);
}
$this->fields = $fields;
return $this;
}
@ -42,4 +46,30 @@ final class HeraldObjectTranscript {
public function getFields() {
return $this->fields;
}
private static function truncateValue($value, $length) {
if (is_string($value)) {
if (strlen($value) <= $length) {
return $value;
} else {
// NOTE: phutil_utf8_shorten() has huge runtime for giant strings.
return phutil_utf8ize(substr($value, 0, $length)."\n<...>");
}
} else if (is_array($value)) {
foreach ($value as $key => $v) {
if ($length <= 0) {
$value['<...>'] = '<...>';
unset($value[$key]);
} else {
$v = self::truncateValue($v, $length);
$length -= strlen($v);
$value[$key] = $v;
}
}
return $value;
} else {
return $value;
}
}
}