Fix limits in queries

Summary: I think this is simpler? Includes test cases.

Test Plan: Ran tests. Loaded /paste/.

Reviewers: vrana, nh

Reviewed By: vrana

CC: aran

Differential Revision: https://secure.phabricator.com/D3209
This commit is contained in:
epriestley
2012-08-08 18:55:07 -07:00
parent 9debf779d6
commit 3460da5f34
2 changed files with 37 additions and 25 deletions

View File

@@ -136,6 +136,36 @@ final class PhabricatorPolicyTestCase extends PhabricatorTestCase {
} }
/**
* Test limits.
*/
public function testLimits() {
$results = array(
$this->buildObject(PhabricatorPolicies::POLICY_USER),
$this->buildObject(PhabricatorPolicies::POLICY_USER),
$this->buildObject(PhabricatorPolicies::POLICY_USER),
$this->buildObject(PhabricatorPolicies::POLICY_USER),
$this->buildObject(PhabricatorPolicies::POLICY_USER),
$this->buildObject(PhabricatorPolicies::POLICY_USER),
);
$query = new PhabricatorPolicyTestQuery();
$query->setResults($results);
$query->setViewer($this->buildUser('user'));
$this->assertEqual(
3,
count($query->setLimit(3)->setOffset(0)->execute()),
'Limits work.');
$this->assertEqual(
2,
count($query->setLimit(3)->setOffset(4)->execute()),
'Limit + offset work.');
}
/** /**
* Test an object for visibility across multiple user specifications. * Test an object for visibility across multiple user specifications.
*/ */

View File

@@ -153,34 +153,16 @@ abstract class PhabricatorPolicyQuery extends PhabricatorOffsetPagedQuery {
$limit = (int)$this->getLimit(); $limit = (int)$this->getLimit();
$count = 0; $count = 0;
$need = null;
if ($offset) {
$need = $offset + $limit; $need = $offset + $limit;
}
$this->willExecute(); $this->willExecute();
do { do {
if ($need) {
// Figure out how many results to load. "0" means "all results". $this->rawResultLimit = min($need - $count, 1024);
$load = 0; } else {
if ($need && ($count < $offset)) { $this->rawResultLimit = 0;
// This cap is just an arbitrary limit to keep memory usage from going
// crazy for large offsets; we can't execute them efficiently, but
// it should be possible to execute them without crashing.
$load = min($need, 1024);
} else if ($limit) {
// Otherwise, just load the number of rows we're after. Note that it
// might be more efficient to load more rows than this (if we expect
// about 5% of objects to be filtered, loading 105% of the limit might
// be better) or fewer rows than this (if we already have 95 rows and
// only need 100, loading only 5 rows might be better), but we currently
// just use the simplest heuristic since we don't have enough data
// about policy queries in the real world to tweak it.
$load = $limit;
} }
$this->rawResultLimit = $load;
$page = $this->loadPage(); $page = $this->loadPage();
@@ -202,13 +184,13 @@ abstract class PhabricatorPolicyQuery extends PhabricatorOffsetPagedQuery {
} }
} }
if (!$load) { if (!$this->rawResultLimit) {
// If we don't have a load count, we loaded all the results. We do // If we don't have a load count, we loaded all the results. We do
// not need to load another page. // not need to load another page.
break; break;
} }
if (count($page) < $load) { if (count($page) < $this->rawResultLimit) {
// If we have a load count but the unfiltered results contained fewer // If we have a load count but the unfiltered results contained fewer
// objects, we know this was the last page of objects; we do not need // objects, we know this was the last page of objects; we do not need
// to load another page because we can deduce it would be empty. // to load another page because we can deduce it would be empty.