1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 08:52:39 +01:00

Make query engines "overheat" instead of stalling when filtering too many results

Summary: Ref T11773. This is an initial first step toward a more complete solution, but should make the worst case much less bad: prior to this change, the worst case was "30 second exeuction timeout". After this patch, the worst case is "no results + explanatory message", which is strictly better.

Test Plan:
Made all feed stories fail policy checks, loaded home page.

  - Before adding overheating: 9,600 queries / 20 seconds
  - After adding overheating: 376 queries / 800ms

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11773

Differential Revision: https://secure.phabricator.com/D16735
This commit is contained in:
epriestley 2016-10-20 08:33:27 -07:00
parent a00e867de0
commit a3253f78ce
2 changed files with 54 additions and 0 deletions

View file

@ -238,6 +238,8 @@ final class PhabricatorApplicationSearchController
$nux_view = null;
}
$is_overheated = $query->getIsOverheated();
if ($nux_view) {
$box->appendChild($nux_view);
} else {
@ -265,6 +267,10 @@ final class PhabricatorApplicationSearchController
$box->appendChild($list->getContent());
}
if ($is_overheated) {
$box->appendChild($this->newOverheatedView($objects));
}
$result_header = $list->getHeader();
if ($result_header) {
$box->setHeader($result_header);
@ -525,4 +531,27 @@ final class PhabricatorApplicationSearchController
->setDropdownMenu($action_list);
}
private function newOverheatedView(array $results) {
if ($results) {
$message = pht(
'Most objects matching your query are not visible to you, so '.
'filtering results is taking a long time. Only some results are '.
'shown. Refine your query to find results more quickly.');
} else {
$message = pht(
'Most objects matching your query are not visible to you, so '.
'filtering results is taking a long time. Refine your query to '.
'find results more quickly.');
}
return id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setFlush(true)
->setTitle(pht('Query Overheated'))
->setErrors(
array(
$message,
));
}
}

View file

@ -44,6 +44,7 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
* and `null` (inherit from parent query, with no exceptions by default).
*/
private $raisePolicyExceptions;
private $isOverheated;
/* -( Query Configuration )------------------------------------------------ */
@ -215,6 +216,14 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
$this->willExecute();
// If we examine and filter significantly more objects than the query
// limit, we stop early. This prevents us from looping through a huge
// number of records when the viewer can see few or none of them. See
// T11773 for some discussion.
$this->isOverheated = false;
$overheat_limit = $limit * 10;
$total_seen = 0;
do {
if ($need) {
$this->rawResultLimit = min($need - $count, 1024);
@ -232,6 +241,8 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
$page = array();
}
$total_seen += count($page);
if ($page) {
$maybe_visible = $this->willFilterPage($page);
if ($maybe_visible) {
@ -302,6 +313,11 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
}
$this->nextPage($page);
if ($overheat_limit && ($total_seen >= $overheat_limit)) {
$this->isOverheated = true;
break;
}
} while (true);
$results = $this->didLoadResults($results);
@ -369,6 +385,15 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
return $this;
}
public function getIsOverheated() {
if ($this->isOverheated === null) {
throw new PhutilInvalidStateException('execute');
}
return $this->isOverheated;
}
/**
* Return a map of all object PHIDs which were loaded in the query but
* filtered out by policy constraints. This allows a caller to distinguish