mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-21 21:10:56 +01:00
Implement an iterator for build log chunks
Summary: Ref T5822. This will make it easier to compress and archive chunks without needing to hold them in memory. Test Plan: Ran a build, looked at some logs. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5822 Differential Revision: https://secure.phabricator.com/D15378
This commit is contained in:
parent
e174cac1b4
commit
6514237c0e
4 changed files with 75 additions and 26 deletions
|
@ -1045,6 +1045,7 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php',
|
'HarbormasterBuildLintMessage' => 'applications/harbormaster/storage/build/HarbormasterBuildLintMessage.php',
|
||||||
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
|
'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php',
|
||||||
'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php',
|
'HarbormasterBuildLogChunk' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunk.php',
|
||||||
|
'HarbormasterBuildLogChunkIterator' => 'applications/harbormaster/storage/build/HarbormasterBuildLogChunkIterator.php',
|
||||||
'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php',
|
'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php',
|
||||||
'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php',
|
'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php',
|
||||||
'HarbormasterBuildMessage' => 'applications/harbormaster/storage/HarbormasterBuildMessage.php',
|
'HarbormasterBuildMessage' => 'applications/harbormaster/storage/HarbormasterBuildMessage.php',
|
||||||
|
@ -5193,6 +5194,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
),
|
),
|
||||||
'HarbormasterBuildLogChunk' => 'HarbormasterDAO',
|
'HarbormasterBuildLogChunk' => 'HarbormasterDAO',
|
||||||
|
'HarbormasterBuildLogChunkIterator' => 'PhutilBufferedIterator',
|
||||||
'HarbormasterBuildLogPHIDType' => 'PhabricatorPHIDType',
|
'HarbormasterBuildLogPHIDType' => 'PhabricatorPHIDType',
|
||||||
'HarbormasterBuildLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'HarbormasterBuildMessage' => array(
|
'HarbormasterBuildMessage' => array(
|
||||||
|
|
|
@ -16,11 +16,6 @@ final class HarbormasterBuildLog
|
||||||
|
|
||||||
const CHUNK_BYTE_LIMIT = 102400;
|
const CHUNK_BYTE_LIMIT = 102400;
|
||||||
|
|
||||||
/**
|
|
||||||
* The log is encoded as plain text.
|
|
||||||
*/
|
|
||||||
const ENCODING_TEXT = 'text';
|
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->rope = new PhutilRope();
|
$this->rope = new PhutilRope();
|
||||||
}
|
}
|
||||||
|
@ -129,6 +124,8 @@ final class HarbormasterBuildLog
|
||||||
|
|
||||||
$chunk_table = id(new HarbormasterBuildLogChunk())->getTableName();
|
$chunk_table = id(new HarbormasterBuildLogChunk())->getTableName();
|
||||||
$chunk_limit = self::CHUNK_BYTE_LIMIT;
|
$chunk_limit = self::CHUNK_BYTE_LIMIT;
|
||||||
|
$encoding_text = HarbormasterBuildLogChunk::CHUNK_ENCODING_TEXT;
|
||||||
|
|
||||||
$rope = $this->rope;
|
$rope = $this->rope;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -147,7 +144,7 @@ final class HarbormasterBuildLog
|
||||||
|
|
||||||
$can_append =
|
$can_append =
|
||||||
($tail) &&
|
($tail) &&
|
||||||
($tail['encoding'] == self::ENCODING_TEXT) &&
|
($tail['encoding'] == $encoding_text) &&
|
||||||
($tail['size'] < $chunk_limit);
|
($tail['size'] < $chunk_limit);
|
||||||
if ($can_append) {
|
if ($can_append) {
|
||||||
$append_id = $tail['id'];
|
$append_id = $tail['id'];
|
||||||
|
@ -176,7 +173,7 @@ final class HarbormasterBuildLog
|
||||||
VALUES (%d, %s, %d, %B)',
|
VALUES (%d, %s, %d, %B)',
|
||||||
$chunk_table,
|
$chunk_table,
|
||||||
$this->getID(),
|
$this->getID(),
|
||||||
self::ENCODING_TEXT,
|
$encoding_text,
|
||||||
$data_size,
|
$data_size,
|
||||||
$append_data);
|
$append_data);
|
||||||
}
|
}
|
||||||
|
@ -185,29 +182,21 @@ final class HarbormasterBuildLog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newChunkIterator() {
|
||||||
|
return new HarbormasterBuildLogChunkIterator($this);
|
||||||
|
}
|
||||||
|
|
||||||
public function getLogText() {
|
public function getLogText() {
|
||||||
// TODO: This won't cope very well if we're pulling like a 700MB
|
// TODO: Remove this method since it won't scale for big logs.
|
||||||
// log file out of the DB. We should probably implement some sort
|
|
||||||
// of optional limit parameter so that when we're rendering out only
|
|
||||||
// 25 lines in the UI, we don't wastefully read in the whole log.
|
|
||||||
|
|
||||||
// We have to read our content out of the database and stitch all of
|
$all_chunks = $this->newChunkIterator();
|
||||||
// the log data back together.
|
|
||||||
$conn = $this->establishConnection('r');
|
|
||||||
$result = queryfx_all(
|
|
||||||
$conn,
|
|
||||||
'SELECT chunk '.
|
|
||||||
'FROM %T '.
|
|
||||||
'WHERE logID = %d '.
|
|
||||||
'ORDER BY id ASC',
|
|
||||||
id(new HarbormasterBuildLogChunk())->getTableName(),
|
|
||||||
$this->getID());
|
|
||||||
|
|
||||||
$content = '';
|
$full_text = array();
|
||||||
foreach ($result as $row) {
|
foreach ($all_chunks as $chunk) {
|
||||||
$content .= $row['chunk'];
|
$full_text[] = $chunk->getChunkDisplayText();
|
||||||
}
|
}
|
||||||
return $content;
|
|
||||||
|
return implode('', $full_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@ final class HarbormasterBuildLogChunk
|
||||||
protected $size;
|
protected $size;
|
||||||
protected $chunk;
|
protected $chunk;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The log is encoded as plain text.
|
||||||
|
*/
|
||||||
|
const CHUNK_ENCODING_TEXT = 'text';
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_TIMESTAMPS => false,
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
|
@ -29,4 +35,21 @@ final class HarbormasterBuildLogChunk
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getChunkDisplayText() {
|
||||||
|
$data = $this->getChunk();
|
||||||
|
$encoding = $this->getEncoding();
|
||||||
|
|
||||||
|
switch ($encoding) {
|
||||||
|
case self::CHUNK_ENCODING_TEXT:
|
||||||
|
// Do nothing, data is already plaintext.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(
|
||||||
|
pht('Unknown log chunk encoding ("%s")!', $encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterBuildLogChunkIterator
|
||||||
|
extends PhutilBufferedIterator {
|
||||||
|
|
||||||
|
private $log;
|
||||||
|
private $cursor;
|
||||||
|
|
||||||
|
public function __construct(HarbormasterBuildLog $log) {
|
||||||
|
$this->log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function didRewind() {
|
||||||
|
$this->cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key() {
|
||||||
|
return $this->current()->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
$results = id(new HarbormasterBuildLogChunk())->loadAllWhere(
|
||||||
|
'logID = %d AND id > %d ORDER BY id ASC LIMIT %d',
|
||||||
|
$this->log->getID(),
|
||||||
|
$this->cursor,
|
||||||
|
$this->getPageSize());
|
||||||
|
|
||||||
|
if ($results) {
|
||||||
|
$this->cursor = last($results)->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue