Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/aphront/console/plugin/DarkConsoleServicesPlugin.php b/src/aphront/console/plugin/DarkConsoleServicesPlugin.php
index c085815648..7f33f9ba6d 100644
--- a/src/aphront/console/plugin/DarkConsoleServicesPlugin.php
+++ b/src/aphront/console/plugin/DarkConsoleServicesPlugin.php
@@ -1,291 +1,292 @@
<?php
final class DarkConsoleServicesPlugin extends DarkConsolePlugin {
protected $observations;
public function getName() {
return 'Services';
}
public function getDescription() {
return 'Information about services.';
}
public static function getQueryAnalyzerHeader() {
return 'X-Phabricator-QueryAnalyzer';
}
public static function isQueryAnalyzerRequested() {
if (!empty($_REQUEST['__analyze__'])) {
return true;
}
$header = AphrontRequest::getHTTPHeader(self::getQueryAnalyzerHeader());
if ($header) {
return true;
}
return false;
}
/**
* @phutil-external-symbol class PhabricatorStartup
*/
public function generateData() {
$should_analyze = self::isQueryAnalyzerRequested();
$log = PhutilServiceProfiler::getInstance()->getServiceCallLog();
foreach ($log as $key => $entry) {
$config = idx($entry, 'config', array());
unset($log[$key]['config']);
if (!$should_analyze) {
$log[$key]['explain'] = array(
'sev' => 7,
'size' => null,
'reason' => 'Disabled',
);
// Query analysis is disabled for this request, so don't do any of it.
continue;
}
if ($entry['type'] != 'query') {
continue;
}
// For each SELECT query, go issue an EXPLAIN on it so we can flag stuff
// causing table scans, etc.
if (preg_match('/^\s*SELECT\b/i', $entry['query'])) {
$conn = PhabricatorEnv::newObjectFromConfig(
'mysql.implementation',
array($entry['config']));
try {
$explain = queryfx_all(
$conn,
'EXPLAIN %Q',
$entry['query']);
$badness = 0;
$size = 1;
$reason = null;
foreach ($explain as $table) {
$size *= (int)$table['rows'];
switch ($table['type']) {
case 'index':
$cur_badness = 1;
$cur_reason = 'Index';
break;
case 'const':
$cur_badness = 1;
$cur_reason = 'Const';
break;
case 'eq_ref';
$cur_badness = 2;
$cur_reason = 'EqRef';
break;
case 'range':
$cur_badness = 3;
$cur_reason = 'Range';
break;
case 'ref':
$cur_badness = 3;
$cur_reason = 'Ref';
break;
case 'fulltext':
$cur_badness = 3;
$cur_reason = 'Fulltext';
break;
case 'ALL':
if (preg_match('/Using where/', $table['Extra'])) {
if ($table['rows'] < 256 && !empty($table['possible_keys'])) {
$cur_badness = 2;
$cur_reason = 'Small Table Scan';
} else {
$cur_badness = 6;
$cur_reason = 'TABLE SCAN!';
}
} else {
$cur_badness = 3;
$cur_reason = 'Whole Table';
}
break;
default:
if (preg_match('/No tables used/i', $table['Extra'])) {
$cur_badness = 1;
$cur_reason = 'No Tables';
} else if (preg_match('/Impossible/i', $table['Extra'])) {
$cur_badness = 1;
$cur_reason = 'Empty';
} else {
$cur_badness = 4;
$cur_reason = "Can't Analyze";
}
break;
}
if ($cur_badness > $badness) {
$badness = $cur_badness;
$reason = $cur_reason;
}
}
$log[$key]['explain'] = array(
'sev' => $badness,
'size' => $size,
'reason' => $reason,
);
} catch (Exception $ex) {
$log[$key]['explain'] = array(
'sev' => 5,
'size' => null,
'reason' => $ex->getMessage(),
);
}
}
}
return array(
'start' => PhabricatorStartup::getStartTime(),
'end' => microtime(true),
'log' => $log,
'analyzeURI' => (string)$this
->getRequestURI()
->alter('__analyze__', true),
'didAnalyze' => $should_analyze,
);
}
public function renderPanel() {
$data = $this->getData();
$log = $data['log'];
$results = array();
$results[] = phutil_tag(
'div',
array('class' => 'dark-console-panel-header'),
array(
phutil_tag(
'a',
array(
'href' => $data['analyzeURI'],
'class' => $data['didAnalyze'] ? 'disabled button' : 'green button',
),
pht('Analyze Query Plans')),
phutil_tag('h1', array(), pht('Calls to External Services')),
phutil_tag('div', array('style' => 'clear: both;')),
));
$page_total = $data['end'] - $data['start'];
$totals = array();
$counts = array();
foreach ($log as $row) {
$totals[$row['type']] = idx($totals, $row['type'], 0) + $row['duration'];
$counts[$row['type']] = idx($counts, $row['type'], 0) + 1;
}
$totals['All Services'] = array_sum($totals);
$counts['All Services'] = array_sum($counts);
$totals['Entire Page'] = $page_total;
$counts['Entire Page'] = 0;
$summary = array();
foreach ($totals as $type => $total) {
$summary[] = array(
$type,
number_format($counts[$type]),
number_format((int)(1000000 * $totals[$type])).' us',
sprintf('%.1f%%', 100 * $totals[$type] / $page_total),
);
}
$summary_table = new AphrontTableView($summary);
$summary_table->setColumnClasses(
array(
'',
'n',
'n',
'wide',
));
$summary_table->setHeaders(
array(
'Type',
'Count',
'Total Cost',
'Page Weight',
));
$results[] = $summary_table->render();
$rows = array();
foreach ($log as $row) {
$analysis = null;
switch ($row['type']) {
case 'query':
$info = $row['query'];
$info = wordwrap($info, 128, "\n", true);
if (!empty($row['explain'])) {
$analysis = phutil_tag(
'span',
array(
'class' => 'explain-sev-'.$row['explain']['sev'],
),
$row['explain']['reason']);
}
break;
case 'connect':
$info = $row['host'].':'.$row['database'];
break;
case 'exec':
$info = $row['command'];
break;
+ case 's3':
case 'conduit':
$info = $row['method'];
break;
case 'http':
$info = $row['uri'];
break;
default:
$info = '-';
break;
}
$rows[] = array(
$row['type'],
'+'.number_format(1000 * ($row['begin'] - $data['start'])).' ms',
number_format(1000000 * $row['duration']).' us',
$info,
$analysis,
);
}
$table = new AphrontTableView($rows);
$table->setColumnClasses(
array(
null,
'n',
'n',
'wide',
'',
));
$table->setHeaders(
array(
'Event',
'Start',
'Duration',
'Details',
'Analysis',
));
$results[] = $table->render();
return phutil_implode_html("\n", $results);
}
}
diff --git a/src/applications/files/engine/PhabricatorS3FileStorageEngine.php b/src/applications/files/engine/PhabricatorS3FileStorageEngine.php
index 1dc8c7d9cd..d64a381c25 100644
--- a/src/applications/files/engine/PhabricatorS3FileStorageEngine.php
+++ b/src/applications/files/engine/PhabricatorS3FileStorageEngine.php
@@ -1,129 +1,152 @@
<?php
/**
* Amazon S3 file storage engine. This engine scales well but is relatively
* high-latency since data has to be pulled off S3.
*
* @task internal Internals
*/
final class PhabricatorS3FileStorageEngine
extends PhabricatorFileStorageEngine {
/* -( Implementation )----------------------------------------------------- */
/**
* This engine identifies as `amazon-s3`.
*/
public function getEngineIdentifier() {
return 'amazon-s3';
}
/**
* Writes file data into Amazon S3.
*/
public function writeFile($data, array $params) {
$s3 = $this->newS3API();
// Generate a random name for this file. We add some directories to it
// (e.g. 'abcdef123456' becomes 'ab/cd/ef123456') to make large numbers of
// files more browsable with web/debugging tools like the S3 administration
// tool.
$seed = Filesystem::readRandomCharacters(20);
$parts = array(
substr($seed, 0, 2),
substr($seed, 2, 2),
substr($seed, 4),
);
$name = 'phabricator/'.implode('/', $parts);
AphrontWriteGuard::willWrite();
+ $profiler = PhutilServiceProfiler::getInstance();
+ $call_id = $profiler->beginServiceCall(
+ array(
+ 'type' => 's3',
+ 'method' => 'putObject',
+ ));
$s3->putObject(
$data,
$this->getBucketName(),
$name,
$acl = 'private');
+ $profiler->endServiceCall($call_id, array());
return $name;
}
/**
* Load a stored blob from Amazon S3.
*/
public function readFile($handle) {
- $result = $this->newS3API()->getObject(
+ $s3 = $this->newS3API();
+ $profiler = PhutilServiceProfiler::getInstance();
+ $call_id = $profiler->beginServiceCall(
+ array(
+ 'type' => 's3',
+ 'method' => 'getObject',
+ ));
+ $result = $s3->getObject(
$this->getBucketName(),
$handle);
+ $profiler->endServiceCall($call_id, array());
// NOTE: The implementation of the API that we're using may respond with
// a successful result that has length 0 and no body property.
if (isset($result->body)) {
return $result->body;
} else {
return '';
}
}
/**
* Delete a blob from Amazon S3.
*/
public function deleteFile($handle) {
AphrontWriteGuard::willWrite();
- $this->newS3API()->deleteObject(
+ $s3 = $this->newS3API();
+ $profiler = PhutilServiceProfiler::getInstance();
+ $call_id = $profiler->beginServiceCall(
+ array(
+ 'type' => 's3',
+ 'method' => 'deleteObject',
+ ));
+ $s3->deleteObject(
$this->getBucketName(),
$handle);
+ $profiler->endServiceCall($call_id, array());
}
/* -( Internals )---------------------------------------------------------- */
/**
* Retrieve the S3 bucket name.
*
* @task internal
*/
private function getBucketName() {
$bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket');
if (!$bucket) {
throw new PhabricatorFileStorageConfigurationException(
"No 'storage.s3.bucket' specified!");
}
return $bucket;
}
/**
* Create a new S3 API object.
*
* @task internal
* @phutil-external-symbol class S3
*/
private function newS3API() {
$libroot = dirname(phutil_get_library_root('phabricator'));
require_once $libroot.'/externals/s3/S3.php';
$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');
$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');
$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');
if (!$access_key || !$secret_key) {
throw new PhabricatorFileStorageConfigurationException(
"Specify 'amazon-s3.access-key' and 'amazon-s3.secret-key'!");
}
if ($endpoint !== null) {
$s3 = new S3($access_key, $secret_key, $use_ssl = true, $endpoint);
} else {
$s3 = new S3($access_key, $secret_key, $use_ssl = true);
}
$s3->setExceptions(true);
return $s3;
}
}
diff --git a/src/applications/paste/query/PhabricatorPasteSearchEngine.php b/src/applications/paste/query/PhabricatorPasteSearchEngine.php
index 79cf87b9f6..209f519ed9 100644
--- a/src/applications/paste/query/PhabricatorPasteSearchEngine.php
+++ b/src/applications/paste/query/PhabricatorPasteSearchEngine.php
@@ -1,193 +1,193 @@
<?php
final class PhabricatorPasteSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Pastes');
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
$languages = $request->getStrList('languages');
if ($request->getBool('noLanguage')) {
$languages[] = null;
}
$saved->setParameter('languages', $languages);
$saved->setParameter('createdStart', $request->getStr('createdStart'));
$saved->setParameter('createdEnd', $request->getStr('createdEnd'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorPasteQuery())
- ->needRawContent(true)
+ ->needContent(true)
->withAuthorPHIDs($saved->getParameter('authorPHIDs', array()))
->withLanguages($saved->getParameter('languages', array()));
$start = $this->parseDateTime($saved->getParameter('createdStart'));
$end = $this->parseDateTime($saved->getParameter('createdEnd'));
if ($start) {
$query->withDateCreatedAfter($start);
}
if ($end) {
$query->withDateCreatedBefore($end);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$phids = $saved_query->getParameter('authorPHIDs', array());
$author_handles = id(new PhabricatorHandleQuery())
->setViewer($this->requireViewer())
->withPHIDs($phids)
->execute();
$languages = $saved_query->getParameter('languages', array());
$no_language = false;
foreach ($languages as $key => $language) {
if ($language === null) {
$no_language = true;
unset($languages[$key]);
continue;
}
}
$form
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('authors')
->setLabel(pht('Authors'))
->setValue($author_handles))
->appendChild(
id(new AphrontFormTextControl())
->setName('languages')
->setLabel(pht('Languages'))
->setValue(implode(', ', $languages)))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'noLanguage',
1,
pht('Find Pastes with no specified language.'),
$no_language));
$this->buildDateRange(
$form,
$saved_query,
'createdStart',
pht('Created After'),
'createdEnd',
pht('Created Before'));
}
protected function getURI($path) {
return '/paste/'.$path;
}
public function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Pastes'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $pastes,
PhabricatorSavedQuery $query) {
return mpull($pastes, 'getAuthorPHID');
}
protected function renderResultList(
array $pastes,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($pastes, 'PhabricatorPaste');
$viewer = $this->requireViewer();
$lang_map = PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($pastes as $paste) {
$created = phabricator_date($paste->getDateCreated(), $viewer);
$author = $handles[$paste->getAuthorPHID()]->renderLink();
- $lines = phutil_split_lines($paste->getRawContent());
+ $lines = phutil_split_lines($paste->getContent());
$preview = id(new PhabricatorSourceCodeView())
->setLimit(5)
->setLines($lines)
->setURI(new PhutilURI($paste->getURI()));
$source_code = phutil_tag(
'div',
array(
'class' => 'phabricator-source-code-summary',
),
$preview);
$line_count = count($lines);
$line_count = pht(
'%s Line(s)',
new PhutilNumber($line_count));
$title = nonempty($paste->getTitle(), pht('(An Untitled Masterwork)'));
$item = id(new PHUIObjectItemView())
->setObjectName('P'.$paste->getID())
->setHeader($title)
->setHref('/P'.$paste->getID())
->setObject($paste)
->addByline(pht('Author: %s', $author))
->addIcon('none', $line_count)
->appendChild($source_code);
$lang_name = $paste->getLanguage();
if ($lang_name) {
$lang_name = idx($lang_map, $lang_name, $lang_name);
$item->addIcon('none', $lang_name);
}
$list->addItem($item);
}
return $list;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 1, 1:31 PM (7 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
164343
Default Alt Text
(18 KB)

Event Timeline