Skip to content

Commit cf25f3d

Browse files
authored
Merge pull request #4197 from rstata/fastbuilder
2 parents 51d16e7 + 5bcba4a commit cf25f3d

18 files changed

+7067
-15
lines changed

build.gradle

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ tasks.named('jmhJar') {
223223
}
224224
}
225225

226+
jmh {
227+
if (project.hasProperty('jmhInclude')) {
228+
includes = [project.property('jmhInclude')]
229+
}
230+
if (project.hasProperty('jmhProfilers')) {
231+
profilers = [project.property('jmhProfilers')]
232+
}
233+
}
234+
226235

227236
task extractWithoutGuava(type: Copy) {
228237
from({ zipTree({ "build/libs/graphql-java-${project.version}.jar" }) }) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package benchmark;
2+
3+
import graphql.schema.idl.FastSchemaGenerator;
4+
import graphql.schema.idl.RuntimeWiring;
5+
import graphql.schema.idl.SchemaGenerator;
6+
import graphql.schema.idl.SchemaParser;
7+
import graphql.schema.idl.TypeDefinitionRegistry;
8+
import org.openjdk.jmh.annotations.Benchmark;
9+
import org.openjdk.jmh.annotations.BenchmarkMode;
10+
import org.openjdk.jmh.annotations.Fork;
11+
import org.openjdk.jmh.annotations.Measurement;
12+
import org.openjdk.jmh.annotations.Mode;
13+
import org.openjdk.jmh.annotations.OutputTimeUnit;
14+
import org.openjdk.jmh.annotations.Scope;
15+
import org.openjdk.jmh.annotations.Setup;
16+
import org.openjdk.jmh.annotations.State;
17+
import org.openjdk.jmh.annotations.Warmup;
18+
import org.openjdk.jmh.infra.Blackhole;
19+
20+
import java.util.concurrent.TimeUnit;
21+
22+
@Warmup(iterations = 2, time = 5)
23+
@Measurement(iterations = 3)
24+
@Fork(2)
25+
@State(Scope.Benchmark)
26+
public class BuildSchemaBenchmark {
27+
28+
static String largeSDL = BenchmarkUtils.loadResource("large-schema-4.graphqls");
29+
30+
private TypeDefinitionRegistry registry;
31+
32+
@Setup
33+
public void setup() {
34+
// Parse SDL once before benchmarks run
35+
registry = new SchemaParser().parse(largeSDL);
36+
}
37+
38+
@Benchmark
39+
@BenchmarkMode(Mode.AverageTime)
40+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
41+
public void benchmarkBuildSchemaAvgTime(Blackhole blackhole) {
42+
blackhole.consume(new SchemaGenerator().makeExecutableSchema(registry, RuntimeWiring.MOCKED_WIRING));
43+
}
44+
45+
@Benchmark
46+
@BenchmarkMode(Mode.AverageTime)
47+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
48+
public void benchmarkBuildSchemaAvgTimeFast(Blackhole blackhole) {
49+
blackhole.consume(new FastSchemaGenerator().makeExecutableSchema(
50+
SchemaGenerator.Options.defaultOptions().withValidation(false),
51+
registry,
52+
RuntimeWiring.MOCKED_WIRING));
53+
}
54+
}

src/jmh/java/benchmark/CreateSchemaBenchmark.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package benchmark;
22

33
import graphql.schema.GraphQLSchema;
4+
import graphql.schema.idl.FastSchemaGenerator;
45
import graphql.schema.idl.RuntimeWiring;
56
import graphql.schema.idl.SchemaGenerator;
67
import graphql.schema.idl.SchemaParser;
@@ -21,7 +22,7 @@
2122
@Fork(2)
2223
public class CreateSchemaBenchmark {
2324

24-
static String largeSDL = BenchmarkUtils.loadResource("large-schema-3.graphqls");
25+
static String largeSDL = BenchmarkUtils.loadResource("large-schema-4.graphqls");
2526

2627
@Benchmark
2728
@BenchmarkMode(Mode.Throughput)
@@ -37,11 +38,26 @@ public void benchmarkLargeSchemaCreateAvgTime(Blackhole blackhole) {
3738
blackhole.consume(createSchema(largeSDL));
3839
}
3940

41+
@Benchmark
42+
@BenchmarkMode(Mode.AverageTime)
43+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
44+
public void benchmarkLargeSchemaCreateAvgTimeFast(Blackhole blackhole) {
45+
blackhole.consume(createSchemaFast(largeSDL));
46+
}
47+
4048
private static GraphQLSchema createSchema(String sdl) {
4149
TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);
4250
return new SchemaGenerator().makeExecutableSchema(registry, RuntimeWiring.MOCKED_WIRING);
4351
}
4452

53+
private static GraphQLSchema createSchemaFast(String sdl) {
54+
TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);
55+
return new FastSchemaGenerator().makeExecutableSchema(
56+
SchemaGenerator.Options.defaultOptions().withValidation(false),
57+
registry,
58+
RuntimeWiring.MOCKED_WIRING);
59+
}
60+
4561
@SuppressWarnings("InfiniteLoopStatement")
4662
/// make this a main method if you want to run it in JProfiler etc..
4763
public static void mainXXX(String[] args) {
@@ -54,4 +70,4 @@ public static void mainXXX(String[] args) {
5470
}
5571
}
5672
}
57-
}
73+
}

src/main/java/graphql/Assert.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import java.util.Collection;
77
import java.util.function.Supplier;
8-
import java.util.regex.Pattern;
98

109
import static java.lang.String.format;
1110

@@ -224,8 +223,6 @@ public static void assertFalse(boolean condition, String msgFmt, Object arg1, Ob
224223

225224
private static final String invalidNameErrorMessage = "Name must be non-null, non-empty and match [_A-Za-z][_0-9A-Za-z]* - was '%s'";
226225

227-
private static final Pattern validNamePattern = Pattern.compile("[_A-Za-z][_0-9A-Za-z]*");
228-
229226
/**
230227
* Validates that the Lexical token name matches the current spec.
231228
* currently non null, non empty,
@@ -234,11 +231,37 @@ public static void assertFalse(boolean condition, String msgFmt, Object arg1, Ob
234231
*
235232
* @return the name if valid, or AssertException if invalid.
236233
*/
237-
public static String assertValidName(String name) {
238-
if (name != null && !name.isEmpty() && validNamePattern.matcher(name).matches()) {
234+
public static String assertValidName(@Nullable String name) {
235+
if (name != null && isValidName(name)) {
239236
return name;
240237
}
241-
return throwAssert(invalidNameErrorMessage, name);
238+
return throwAssert(invalidNameErrorMessage, String.valueOf(name));
239+
}
240+
241+
/**
242+
* Fast character-by-character validation without regex.
243+
* Checks if name matches [_A-Za-z][_0-9A-Za-z]*
244+
*/
245+
private static boolean isValidName(String name) {
246+
if (name.isEmpty()) {
247+
return false;
248+
}
249+
250+
// First character must be [_A-Za-z]
251+
char first = name.charAt(0);
252+
if (!(first == '_' || (first >= 'A' && first <= 'Z') || (first >= 'a' && first <= 'z'))) {
253+
return false;
254+
}
255+
256+
// Remaining characters must be [_0-9A-Za-z]
257+
for (int i = 1; i < name.length(); i++) {
258+
char c = name.charAt(i);
259+
if (!(c == '_' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) {
260+
return false;
261+
}
262+
}
263+
264+
return true;
242265
}
243266

244267
private static <T> T throwAssert(String format, Object... args) {

0 commit comments

Comments
 (0)