Unverified 提交 871d372b authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1132 from katzyn/visitor

Reduce allocation of ExpressionVisitor instances
...@@ -1435,20 +1435,18 @@ public class Select extends Query { ...@@ -1435,20 +1435,18 @@ public class Select extends Query {
default: default:
} }
ExpressionVisitor v2 = visitor.incrementQueryLevel(1); ExpressionVisitor v2 = visitor.incrementQueryLevel(1);
boolean result = true;
for (Expression e : expressions) { for (Expression e : expressions) {
if (!e.isEverything(v2)) { if (!e.isEverything(v2)) {
result = false; return false;
break;
} }
} }
if (result && condition != null && !condition.isEverything(v2)) { if (condition != null && !condition.isEverything(v2)) {
result = false; return false;
} }
if (result && having != null && !having.isEverything(v2)) { if (having != null && !having.isEverything(v2)) {
result = false; return false;
} }
return result; return true;
} }
@Override @Override
......
...@@ -61,6 +61,37 @@ public class ExpressionVisitor { ...@@ -61,6 +61,37 @@ public class ExpressionVisitor {
public static final ExpressionVisitor EVALUATABLE_VISITOR = public static final ExpressionVisitor EVALUATABLE_VISITOR =
new ExpressionVisitor(EVALUATABLE); new ExpressionVisitor(EVALUATABLE);
/**
* Count of cached INDEPENDENT and EVALUATABLE visitors with different query
* level.
*/
private static final int CACHED = 8;
/**
* INDEPENDENT listeners with query level 0, 1, ...
*/
private static final ExpressionVisitor[] INDEPENDENT_VISITORS;
/**
* EVALUATABLE listeners with query level 0, 1, ...
*/
private static final ExpressionVisitor[] EVALUATABLE_VISITORS;
static {
ExpressionVisitor[] a = new ExpressionVisitor[CACHED];
a[0] = INDEPENDENT_VISITOR;
for (int i = 1; i < CACHED; i++) {
a[i] = new ExpressionVisitor(INDEPENDENT, i);
}
INDEPENDENT_VISITORS = a;
a = new ExpressionVisitor[CACHED];
a[0] = EVALUATABLE_VISITOR;
for (int i = 1; i < CACHED; i++) {
a[i] = new ExpressionVisitor(EVALUATABLE, i);
}
EVALUATABLE_VISITORS = a;
}
/** /**
* Request to set the latest modification id (addDataModificationId). * Request to set the latest modification id (addDataModificationId).
*/ */
...@@ -148,6 +179,17 @@ public class ExpressionVisitor { ...@@ -148,6 +179,17 @@ public class ExpressionVisitor {
this.maxDataModificationId = null; this.maxDataModificationId = null;
} }
private ExpressionVisitor(int type, int queryLevel) {
this.type = type;
this.queryLevel = queryLevel;
this.dependencies = null;
this.columns1 = null;
this.columns2 = null;
this.table = null;
this.resolver = null;
this.maxDataModificationId = null;
}
/** /**
* Create a new visitor object to collect dependencies. * Create a new visitor object to collect dependencies.
* *
...@@ -245,11 +287,18 @@ public class ExpressionVisitor { ...@@ -245,11 +287,18 @@ public class ExpressionVisitor {
* Increment or decrement the query level. * Increment or decrement the query level.
* *
* @param offset 1 to increment, -1 to decrement * @param offset 1 to increment, -1 to decrement
* @return a clone of this expression visitor, with the changed query level * @return this visitor or its clone with the changed query level
*/ */
public ExpressionVisitor incrementQueryLevel(int offset) { public ExpressionVisitor incrementQueryLevel(int offset) {
return new ExpressionVisitor(type, queryLevel + offset, dependencies, if (type == INDEPENDENT) {
columns1, table, resolver, maxDataModificationId, columns2); offset += queryLevel;
return offset < CACHED ? INDEPENDENT_VISITORS[offset] : new ExpressionVisitor(INDEPENDENT, offset);
} else if (type == EVALUATABLE) {
offset += queryLevel;
return offset < CACHED ? EVALUATABLE_VISITORS[offset] : new ExpressionVisitor(EVALUATABLE, offset);
} else {
return this;
}
} }
/** /**
...@@ -287,6 +336,7 @@ public class ExpressionVisitor { ...@@ -287,6 +336,7 @@ public class ExpressionVisitor {
} }
int getQueryLevel() { int getQueryLevel() {
assert type == INDEPENDENT || type == EVALUATABLE;
return queryLevel; return queryLevel;
} }
......
...@@ -45,6 +45,7 @@ import org.h2.test.utils.ProxyCodeGenerator; ...@@ -45,6 +45,7 @@ import org.h2.test.utils.ProxyCodeGenerator;
import org.h2.test.utils.ResultVerifier; import org.h2.test.utils.ResultVerifier;
import org.h2.test.utils.SelfDestructor; import org.h2.test.utils.SelfDestructor;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.util.Utils;
/** /**
* The base class for all tests. * The base class for all tests.
...@@ -140,7 +141,14 @@ public abstract class TestBase { ...@@ -140,7 +141,14 @@ public abstract class TestBase {
init(conf); init(conf);
start = System.nanoTime(); start = System.nanoTime();
test(); test();
println(""); if (!config.mvStore) {
/*
* This code is here to debug memory issues with PageStore testing on Travis.
*/
println("(" + (Utils.getMemoryUsed() >> 10) + " MiB used after)");
} else {
println("");
}
} catch (Throwable e) { } catch (Throwable e) {
println("FAIL " + e.toString()); println("FAIL " + e.toString());
logError("FAIL " + e.toString(), e); logError("FAIL " + e.toString(), e);
......
...@@ -18,6 +18,7 @@ import java.util.Random; ...@@ -18,6 +18,7 @@ import java.util.Random;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.db.Db; import org.h2.test.db.Db;
import org.h2.test.db.Db.Prepared; import org.h2.test.db.Db.Prepared;
import org.h2.util.Utils;
/** /**
* This test executes random SQL statements to test if optimizations are working * This test executes random SQL statements to test if optimizations are working
...@@ -102,12 +103,12 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -102,12 +103,12 @@ public class TestFuzzOptimizations extends TestBase {
int size = getSize(100, 1000); int size = getSize(100, 1000);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
long seed = seedGenerator.nextLong(); long seed = seedGenerator.nextLong();
println("seed: " + seed); println("testIn() seed: " + seed);
Random random = new Random(seed); Random random = new Random(seed);
ArrayList<String> params = new ArrayList<>(); ArrayList<String> params = new ArrayList<>();
String condition = getRandomCondition(random, params, columns, String condition = getRandomCondition(random, params, columns,
compares, values); compares, values);
String message = "seed: " + seed + " " + condition; String message = "testIn() seed: " + seed + " " + condition;
executeAndCompare(condition, params, message); executeAndCompare(condition, params, message);
if (params.size() > 0) { if (params.size() > 0) {
for (int j = 0; j < params.size(); j++) { for (int j = 0; j < params.size(); j++) {
...@@ -116,9 +117,16 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -116,9 +117,16 @@ public class TestFuzzOptimizations extends TestBase {
} }
executeAndCompare(condition, params, message); executeAndCompare(condition, params, message);
} }
if (!config.mvStore) {
/*
* Travis tests have problems with automatic garbage collection, so request a GC
* explicitly and print its results.
*/
println((Utils.getMemoryUsed() >> 10) + " MiB used");
}
} }
executeAndCompare("a >=0 and b in(?, 2) and a in(1, ?, null)", Arrays.asList("10", "2"), executeAndCompare("a >=0 and b in(?, 2) and a in(1, ?, null)", Arrays.asList("10", "2"),
"seed=-6191135606105920350L"); "testIn() seed=-6191135606105920350L");
db.execute("drop table test0, test1"); db.execute("drop table test0, test1");
} }
...@@ -192,7 +200,7 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -192,7 +200,7 @@ public class TestFuzzOptimizations extends TestBase {
db.execute("UPDATE TEST SET B = NULL WHERE B = 0"); db.execute("UPDATE TEST SET B = NULL WHERE B = 0");
Random random = new Random(); Random random = new Random();
long seed = random.nextLong(); long seed = random.nextLong();
println("seed: " + seed); println("testInSelect() seed: " + seed);
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
String column = random.nextBoolean() ? "A" : "B"; String column = random.nextBoolean() ? "A" : "B";
String value = new String[] { "NULL", "0", "A", "B" }[random.nextInt(4)]; String value = new String[] { "NULL", "0", "A", "B" }[random.nextInt(4)];
...@@ -206,7 +214,7 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -206,7 +214,7 @@ public class TestFuzzOptimizations extends TestBase {
" FROM TEST I WHERE I." + compare + "=?) ORDER BY 1, 2"; " FROM TEST I WHERE I." + compare + "=?) ORDER BY 1, 2";
List<Map<String, Object>> a = db.prepare(sql1).set(x).query(); List<Map<String, Object>> a = db.prepare(sql1).set(x).query();
List<Map<String, Object>> b = db.prepare(sql2).set(x).query(); List<Map<String, Object>> b = db.prepare(sql2).set(x).query();
assertTrue("seed: " + seed + " sql: " + sql1 + assertTrue("testInSelect() seed: " + seed + " sql: " + sql1 +
" a: " + a + " b: " + b, a.equals(b)); " a: " + a + " b: " + b, a.equals(b));
} }
db.execute("DROP TABLE TEST"); db.execute("DROP TABLE TEST");
...@@ -217,7 +225,7 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -217,7 +225,7 @@ public class TestFuzzOptimizations extends TestBase {
db.execute("CREATE TABLE TEST(A INT, B INT, C INT)"); db.execute("CREATE TABLE TEST(A INT, B INT, C INT)");
Random random = new Random(); Random random = new Random();
long seed = random.nextLong(); long seed = random.nextLong();
println("seed: " + seed); println("testGroupSorted() seed: " + seed);
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
Prepared p = db.prepare("INSERT INTO TEST VALUES(?, ?, ?)"); Prepared p = db.prepare("INSERT INTO TEST VALUES(?, ?, ?)");
p.set(new String[] { null, "0", "1", "2" }[random.nextInt(4)]); p.set(new String[] { null, "0", "1", "2" }[random.nextInt(4)]);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论