Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bin/jmh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

BRANCH=$(git rev-parse --abbrev-ref HEAD)
JAR="build/libs/graphql-java-0.0.0-$BRANCH-SNAPSHOT-jmh.jar"
echo "build and then running jmh for $JAR"

./gradlew clean jmhJar

java -jar "$JAR" "$@"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little helper to make it easier to run the JMH tests on the command line

121 changes: 121 additions & 0 deletions src/jmh/java/benchmark/CreateExtendedSchemaBenchmark.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package benchmark;

import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;

import static benchmark.BenchmarkUtils.runInToolingForSomeTimeThenExit;

/**
* This JMH
*/
@Warmup(iterations = 2, time = 5)
@Measurement(iterations = 3)
@Fork(3)
public class CreateExtendedSchemaBenchmark {

private static final String SDL = mkSDL();

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MINUTES)
public void benchmarkLargeSchemaCreate(Blackhole blackhole) {
blackhole.consume(createSchema(SDL));
}

@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public void benchmarkLargeSchemaCreateAvgTime(Blackhole blackhole) {
blackhole.consume(createSchema(SDL));
}

private static GraphQLSchema createSchema(String sdl) {
TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);
return new SchemaGenerator().makeExecutableSchema(registry, RuntimeWiring.MOCKED_WIRING);
}

/* something like
type Query { q : String } interface I { f : String }
interface I1 implements I {
f : String
f1 : String
}
type O1_1 implements I1 & I {
f : String
f1 : String
}
type O1_2 implements I1 & I {
f : String
f1 : String
}
*/
private static String mkSDL() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a benchmark with lots of extends type X and interfaces

int numTypes = 10000;
int numExtends = 10;

StringBuilder sb = new StringBuilder();
sb.append("type Query { q : String } interface I { f : String } interface X { x : String }\n");
for (int i = 0; i < numTypes; i++) {
sb.append("interface I").append(i).append(" implements I { \n")
.append("\tf : String \n")
.append("\tf").append(i).append(" : String \n").append("}\n");

sb.append("type O").append(i).append(" implements I").append(i).append(" & I { \n")
.append("\tf : String \n")
.append("\tf").append(i).append(" : String \n")
.append("}\n");

sb.append("extend type O").append(i).append(" implements X").append(" { \n")
.append("\tx : String \n")
.append("}\n");

for (int j = 0; j < numExtends; j++) {
sb.append("extend type O").append(i).append(" { \n")
.append("\textendedF").append(j).append(" : String \n")
.append("}\n");

}
}
return sb.toString();
}

public static void main(String[] args) throws RunnerException {
try {
runAtStartup();
} catch (Throwable e) {
throw new RuntimeException(e);
}
Options opt = new OptionsBuilder()
.include("benchmark.CreateExtendedSchemaBenchmark")
.build();

new Runner(opt).run();
}

private static void runAtStartup() {
runInToolingForSomeTimeThenExit(
() -> {
},
() -> createSchema(SDL),
() -> {
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ private void checkArgValueMatchesAllowedTypeName(List<GraphQLError> errors, Valu
}

String allowedTypeName = ((TypeName) allowedArgType).getName();
TypeDefinition<?> allowedTypeDefinition = typeRegistry.getType(allowedTypeName)
.orElseThrow(() -> new AssertException(format("Directive unknown argument type '%s'. This should have been validated before.", allowedTypeName)));
TypeDefinition<?> allowedTypeDefinition = typeRegistry.getTypeOrNull(allowedTypeName);
if (allowedTypeDefinition == null) {
throw new AssertException(format("Directive unknown argument type '%s'. This should have been validated before.", allowedTypeName));
}

if (allowedTypeDefinition instanceof ScalarTypeDefinition) {
checkArgValueMatchesAllowedScalar(errors, instanceValue, (ScalarTypeDefinition) allowedTypeDefinition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
import graphql.PublicApi;
import graphql.language.DirectiveDefinition;
import graphql.language.EnumTypeExtensionDefinition;
import graphql.language.ImplementingTypeDefinition;
import graphql.language.InputObjectTypeExtensionDefinition;
import graphql.language.InterfaceTypeDefinition;
import graphql.language.InterfaceTypeExtensionDefinition;
import graphql.language.ObjectTypeDefinition;
import graphql.language.ObjectTypeExtensionDefinition;
import graphql.language.SDLDefinition;
import graphql.language.ScalarTypeDefinition;
import graphql.language.ScalarTypeExtensionDefinition;
import graphql.language.SchemaExtensionDefinition;
import graphql.language.Type;
import graphql.language.TypeDefinition;
import graphql.language.UnionTypeExtensionDefinition;
import graphql.schema.idl.errors.SchemaProblem;
Expand All @@ -34,6 +38,7 @@
@PublicApi
@NullMarked
public class ImmutableTypeDefinitionRegistry extends TypeDefinitionRegistry {

ImmutableTypeDefinitionRegistry(TypeDefinitionRegistry registry) {
super(
copyOf(registry.objectTypeExtensions),
Expand All @@ -51,6 +56,7 @@ public class ImmutableTypeDefinitionRegistry extends TypeDefinitionRegistry {
);
}


private UnsupportedOperationException unsupportedOperationException() {
return new UnsupportedOperationException("The TypeDefinitionRegistry is in read only mode");
}
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/graphql/schema/idl/ImplementingTypesChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Objects;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting rid of the Optional methods and using the getOrNull ones

import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.Function;
Expand Down Expand Up @@ -73,7 +73,7 @@ void checkImplementingTypes(List<GraphQLError> errors, TypeDefinitionRegistry ty
private void checkImplementingType(
List<GraphQLError> errors,
TypeDefinitionRegistry typeRegistry,
ImplementingTypeDefinition type) {
ImplementingTypeDefinition<?> type) {

Map<InterfaceTypeDefinition, ImplementingTypeDefinition> implementedInterfaces =
checkInterfacesNotImplementedMoreThanOnce(errors, type, typeRegistry);
Expand Down Expand Up @@ -172,7 +172,7 @@ private void checkInterfaceIsImplemented(

private void checkArgumentConsistency(
String typeOfType,
ImplementingTypeDefinition objectTypeDef,
ImplementingTypeDefinition<?> objectTypeDef,
InterfaceTypeDefinition interfaceTypeDef,
FieldDefinition objectFieldDef,
FieldDefinition interfaceFieldDef,
Expand Down Expand Up @@ -211,7 +211,7 @@ private void checkArgumentConsistency(
}

private Map<InterfaceTypeDefinition, List<ImplementingTypeDefinition>> getLogicallyImplementedInterfaces(
ImplementingTypeDefinition type,
ImplementingTypeDefinition<?> type,
TypeDefinitionRegistry typeRegistry
) {

Expand Down Expand Up @@ -255,18 +255,17 @@ private <T> BinaryOperator<T> mergeFirstValue() {
return (v1, v2) -> v1;
}

private Optional<InterfaceTypeDefinition> toInterfaceTypeDefinition(Type type, TypeDefinitionRegistry typeRegistry) {
private InterfaceTypeDefinition toInterfaceTypeDefinition(Type<?> type, TypeDefinitionRegistry typeRegistry) {
TypeInfo typeInfo = TypeInfo.typeInfo(type);
TypeName unwrapped = typeInfo.getTypeName();

return typeRegistry.getType(unwrapped, InterfaceTypeDefinition.class);
return typeRegistry.getTypeOrNull(unwrapped, InterfaceTypeDefinition.class);
}

private Set<InterfaceTypeDefinition> toInterfaceTypeDefinitions(TypeDefinitionRegistry typeRegistry, Collection<Type> implementsTypes) {
return implementsTypes.stream()
.map(t -> toInterfaceTypeDefinition(t, typeRegistry))
.filter(Optional::isPresent)
.map(Optional::get)
.filter(Objects::nonNull)
.collect(toSet());
}
}
16 changes: 8 additions & 8 deletions src/main/java/graphql/schema/idl/SchemaExtensionsChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ static List<OperationTypeDefinition> checkSchemaInvariants(List<GraphQLError> er

// ensure we have a "query" one
Optional<OperationTypeDefinition> query = operationTypeDefinitions.stream().filter(op -> "query".equals(op.getName())).findFirst();
if (!query.isPresent()) {
if (query.isEmpty()) {
// its ok if they have a type named Query
Optional<TypeDefinition> queryType = typeRegistry.getType("Query");
if (!queryType.isPresent()) {
TypeDefinition<?> queryType = typeRegistry.getTypeOrNull("Query");
if (queryType == null) {
errors.add(new QueryOperationMissingError());
}
}
Expand Down Expand Up @@ -117,13 +117,13 @@ private static Consumer<OperationTypeDefinition> checkOperationTypesExist(TypeDe
private static Consumer<OperationTypeDefinition> checkOperationTypesAreObjects(TypeDefinitionRegistry typeRegistry, List<GraphQLError> errors) {
return op -> {
// make sure it is defined as a ObjectTypeDef
Type queryType = op.getTypeName();
Optional<TypeDefinition> type = typeRegistry.getType(queryType);
type.ifPresent(typeDef -> {
if (!(typeDef instanceof ObjectTypeDefinition)) {
Type<?> queryType = op.getTypeName();
TypeDefinition<?> type = typeRegistry.getTypeOrNull(queryType);
if (type != null) {
if (!(type instanceof ObjectTypeDefinition)) {
errors.add(new OperationTypesMustBeObjects(op));
}
});
}
};
}

Expand Down
36 changes: 18 additions & 18 deletions src/main/java/graphql/schema/idl/SchemaGeneratorHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,12 @@ public TypeDefinitionRegistry getTypeRegistry() {
}

TypeDefinition<?> getTypeDefinition(Type<?> type) {
Optional<TypeDefinition> optionalTypeDefinition = typeRegistry.getType(type);

return optionalTypeDefinition.orElseThrow(
() -> new AssertException(format(" type definition for type '%s' not found", type))
);
TypeDefinition<?> typeDefinition = typeRegistry.getTypeOrNull(type);
if (typeDefinition != null) {
return typeDefinition;
} else {
throw new AssertException(format(" type definition for type '%s' not found", type));
}
}

boolean stackContains(TypeInfo typeInfo) {
Expand Down Expand Up @@ -905,22 +906,21 @@ void buildOperations(BuildContext buildCtx, GraphQLSchema.Builder schemaBuilder)
GraphQLObjectType subscription;

Optional<OperationTypeDefinition> queryOperation = getOperationNamed("query", operationTypeDefs);
if (!queryOperation.isPresent()) {
@SuppressWarnings({"OptionalGetWithoutIsPresent"})
TypeDefinition<?> queryTypeDef = typeRegistry.getType("Query").get();
if (queryOperation.isEmpty()) {
TypeDefinition<?> queryTypeDef = Objects.requireNonNull(typeRegistry.getTypeOrNull("Query"));
query = buildOutputType(buildCtx, TypeName.newTypeName().name(queryTypeDef.getName()).build());
} else {
query = buildOperation(buildCtx, queryOperation.get());
}
schemaBuilder.query(query);

Optional<OperationTypeDefinition> mutationOperation = getOperationNamed("mutation", operationTypeDefs);
if (!mutationOperation.isPresent()) {
if (!typeRegistry.schemaDefinition().isPresent()) {
if (mutationOperation.isEmpty()) {
if (typeRegistry.schemaDefinition().isEmpty()) {
// If no schema definition, then there is no schema keyword. Default to using type called Mutation
Optional<TypeDefinition> mutationTypeDef = typeRegistry.getType("Mutation");
if (mutationTypeDef.isPresent()) {
mutation = buildOutputType(buildCtx, TypeName.newTypeName().name(mutationTypeDef.get().getName()).build());
TypeDefinition<?> mutationTypeDef = typeRegistry.getTypeOrNull("Mutation");
if (mutationTypeDef != null) {
mutation = buildOutputType(buildCtx, TypeName.newTypeName().name(mutationTypeDef.getName()).build());
schemaBuilder.mutation(mutation);
}
}
Expand All @@ -930,12 +930,12 @@ void buildOperations(BuildContext buildCtx, GraphQLSchema.Builder schemaBuilder)
}

Optional<OperationTypeDefinition> subscriptionOperation = getOperationNamed("subscription", operationTypeDefs);
if (!subscriptionOperation.isPresent()) {
if (!typeRegistry.schemaDefinition().isPresent()) {
if (subscriptionOperation.isEmpty()) {
if (typeRegistry.schemaDefinition().isEmpty()) {
// If no schema definition, then there is no schema keyword. Default to using type called Subscription
Optional<TypeDefinition> subscriptionTypeDef = typeRegistry.getType("Subscription");
if (subscriptionTypeDef.isPresent()) {
subscription = buildOutputType(buildCtx, TypeName.newTypeName().name(subscriptionTypeDef.get().getName()).build());
TypeDefinition<?> subscriptionTypeDef = typeRegistry.getTypeOrNull("Subscription");
if (subscriptionTypeDef != null) {
subscription = buildOutputType(buildCtx, TypeName.newTypeName().name(subscriptionTypeDef.getName()).build());
schemaBuilder.subscription(subscription);
}
}
Expand Down
17 changes: 9 additions & 8 deletions src/main/java/graphql/schema/idl/SchemaTypeChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand Down Expand Up @@ -333,17 +332,19 @@ private void checkFieldTypesPresent(TypeDefinitionRegistry typeRegistry, List<Gr

private Consumer<Type> checkTypeExists(String typeOfType, TypeDefinitionRegistry typeRegistry, List<GraphQLError> errors, TypeDefinition typeDefinition) {
return t -> {
TypeName unwrapped = TypeInfo.typeInfo(t).getTypeName();
if (!typeRegistry.hasType(unwrapped)) {
String name = TypeInfo.typeName(t);
if (!typeRegistry.hasType(name)) {
TypeName unwrapped = TypeInfo.typeInfo(t).getTypeName();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

faster look up - we only create a TypeInfo if its in error

errors.add(new MissingTypeError(typeOfType, typeDefinition, unwrapped));
}
};
}

private Consumer<Type> checkTypeExists(TypeDefinitionRegistry typeRegistry, List<GraphQLError> errors, String typeOfType, Node element, String elementName) {
return ivType -> {
TypeName unwrapped = TypeInfo.typeInfo(ivType).getTypeName();
if (!typeRegistry.hasType(unwrapped)) {
String name = TypeInfo.typeName(ivType);
if (!typeRegistry.hasType(name)) {
TypeName unwrapped = TypeInfo.typeInfo(ivType).getTypeName();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

faster look up - we only create a TypeInfo if its in error

errors.add(new MissingTypeError(typeOfType, element, elementName, unwrapped));
}
};
Expand All @@ -353,10 +354,10 @@ private Consumer<? super Type> checkInterfaceTypeExists(TypeDefinitionRegistry t
return t -> {
TypeInfo typeInfo = TypeInfo.typeInfo(t);
TypeName unwrapped = typeInfo.getTypeName();
Optional<TypeDefinition> type = typeRegistry.getType(unwrapped);
if (!type.isPresent()) {
TypeDefinition<?> type = typeRegistry.getTypeOrNull(unwrapped);
if (type == null) {
errors.add(new MissingInterfaceTypeError("interface", typeDefinition, unwrapped));
} else if (!(type.get() instanceof InterfaceTypeDefinition)) {
} else if (!(type instanceof InterfaceTypeDefinition)) {
errors.add(new MissingInterfaceTypeError("interface", typeDefinition, unwrapped));
}
};
Expand Down
Loading