Fix limit handling in QueryProcessor

This was a mess, and hasn't been working for a long time. The test for
_more_changes added in this change does not pass prior to this change.

The only way we ever communicated that extra results were present out
of QueryProcessor was by including one more result. But different
pieces of the code were rarely clear on whether they should be
expecting an extra result or not. Moreover, there were three different
limits that were considered, and they were all given unhelpful names
like "limit" and "maxLimit."

Improving this situation substantially requires doing something like
what the end result is from the REST API: including for each list of
results a boolean indicating whether there are more results available.
Do this with a QueryResult class encapsulating these fields. This
class also includes the original query string and rewritten predicate
intermediates, which can help with debugging.

After this change, the semantics of the limits should be more clear.
The limit computation uses more helpful variable names, and enforces
that we always request a limit of n+1 from the secondary index.
However, this extra result never escapes to callers in a QueryResult
from QueryProcessor.

This also required changes to the query rewriter to replace all limit
predicates within the query with a fixed value that is always
different from any limit predicate in the original query. This may
actually make IndexRewriteTest a little easier to understand, as prior
to this change a different limit would appear in the IndexChangedQuery
portions than at the top level.

Change-Id: I4fcf7db0136fd77dbe91b20258ae80a9797a1af9
This commit is contained in:
Dave Borowitz
2014-12-22 11:18:22 -08:00
parent f187399539
commit db52c00bc3
12 changed files with 211 additions and 121 deletions

View File

@@ -97,7 +97,7 @@ public class IndexRewriteTest {
parse("-status:abandoned (status:open OR status:merged)");
assertEquals(
query(parse("status:new OR status:submitted OR status:draft OR status:merged")),
rewrite.rewrite(in, 0));
rewrite.rewrite(in, 0, DEFAULT_MAX_QUERY_LIMIT));
}
@Test
@@ -158,24 +158,26 @@ public class IndexRewriteTest {
}
@Test
public void testLimit() throws Exception {
Predicate<ChangeData> in = parse("file:a limit:3");
Predicate<ChangeData> out = rewrite(in);
public void testLimitArgumentOverridesAllLimitPredicates() throws Exception {
Predicate<ChangeData> in = parse("limit:1 file:a limit:3");
Predicate<ChangeData> out = rewrite(in, 5);
assertSame(AndSource.class, out.getClass());
assertEquals(ImmutableList.of(
query(in.getChild(0), 3),
in.getChild(1)),
query(in.getChild(1), 5),
parse("limit:5"),
parse("limit:5")),
out.getChildren());
}
@Test
public void testStartIncreasesLimit() throws Exception {
int n = 3;
Predicate<ChangeData> f = parse("file:a");
Predicate<ChangeData> l = parse("limit:3");
Predicate<ChangeData> l = parse("limit:" + n);
Predicate<ChangeData> in = and(f, l);
assertEquals(and(query(f, 3), l), rewrite.rewrite(in, 0));
assertEquals(and(query(f, 4), l), rewrite.rewrite(in, 1));
assertEquals(and(query(f, 5), l), rewrite.rewrite(in, 2));
assertEquals(and(query(f, 3), parse("limit:3")), rewrite.rewrite(in, 0, n));
assertEquals(and(query(f, 4), parse("limit:4")), rewrite.rewrite(in, 1, n));
assertEquals(and(query(f, 5), parse("limit:5")), rewrite.rewrite(in, 2, n));
}
@Test
@@ -220,7 +222,12 @@ public class IndexRewriteTest {
private Predicate<ChangeData> rewrite(Predicate<ChangeData> in)
throws QueryParseException {
return rewrite.rewrite(in, 0);
return rewrite.rewrite(in, 0, DEFAULT_MAX_QUERY_LIMIT);
}
private Predicate<ChangeData> rewrite(Predicate<ChangeData> in, int limit)
throws QueryParseException {
return rewrite.rewrite(in, 0, limit);
}
private IndexedChangeQuery query(Predicate<ChangeData> p)

View File

@@ -543,9 +543,22 @@ public abstract class AbstractQueryChangesTest {
List<ChangeInfo> results;
for (int i = 1; i <= n + 2; i++) {
int expectedSize;
Boolean expectedMoreChanges;
if (i < n) {
expectedSize = i;
expectedMoreChanges = true;
} else {
expectedSize = n;
expectedMoreChanges = null;
}
results = query("status:new limit:" + i);
assertThat(results).hasSize(Math.min(i, n));
String msg = "i=" + i;
assert_().withFailureMessage(msg).that(results).hasSize(expectedSize);
assertResultEquals(last, results.get(0));
assert_().withFailureMessage(msg)
.that(results.get(results.size() - 1)._moreChanges)
.isEqualTo(expectedMoreChanges);
}
}