Skip to content

Commit 88198e1

Browse files
committed
Make ExecutionStepInfo values be lazy
This will improve memory usage if you don't use the ESI arguments, and it will reduce CPU usage somewhat in heavy systems by doing less work (albeit it a small amount)
1 parent 0b887a9 commit 88198e1

File tree

7 files changed

+47
-42
lines changed

7 files changed

+47
-42
lines changed

src/main/java/graphql/TypeResolutionEnvironment.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import graphql.schema.GraphQLType;
1111

1212
import java.util.Map;
13+
import java.util.function.Supplier;
1314

1415
/**
1516
* This is passed to a {@link graphql.schema.TypeResolver} to help with object type resolution.
@@ -21,7 +22,7 @@
2122
public class TypeResolutionEnvironment {
2223

2324
private final Object object;
24-
private final ImmutableMapWithNullValues<String, Object> arguments;
25+
private final Supplier<ImmutableMapWithNullValues<String, Object>> arguments;
2526
private final MergedField field;
2627
private final GraphQLType fieldType;
2728
private final GraphQLSchema schema;
@@ -33,7 +34,7 @@ public class TypeResolutionEnvironment {
3334
@Internal
3435
public TypeResolutionEnvironment(TypeResolutionParameters parameters) {
3536
this.object = parameters.getValue();
36-
this.arguments = ImmutableMapWithNullValues.copyOf(parameters.getArgumentValues());
37+
this.arguments = () -> ImmutableMapWithNullValues.copyOf(parameters.getArgumentValues());
3738
this.field = parameters.getField();
3839
this.fieldType = parameters.getFieldType();
3940
this.schema = parameters.getSchema();
@@ -60,7 +61,7 @@ public <T> T getObject() {
6061
* @return the runtime arguments to this the graphql field
6162
*/
6263
public Map<String, Object> getArguments() {
63-
return arguments;
64+
return arguments.get();
6465
}
6566

6667
/**

src/main/java/graphql/execution/ExecutionStepInfo.java

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.util.Map;
1313
import java.util.function.Consumer;
14+
import java.util.function.Supplier;
1415

1516
import static graphql.Assert.assertNotNull;
1617
import static graphql.Assert.assertTrue;
@@ -64,28 +65,23 @@ public class ExecutionStepInfo {
6465
private final MergedField field;
6566
private final GraphQLFieldDefinition fieldDefinition;
6667
private final GraphQLObjectType fieldContainer;
67-
private final ImmutableMapWithNullValues<String, Object> arguments;
68-
69-
private ExecutionStepInfo(GraphQLOutputType type,
70-
GraphQLFieldDefinition fieldDefinition,
71-
MergedField field,
72-
ResultPath path,
73-
ExecutionStepInfo parent,
74-
ImmutableMapWithNullValues<String, Object> arguments,
75-
GraphQLObjectType fieldsContainer) {
76-
this.fieldDefinition = fieldDefinition;
77-
this.field = field;
78-
this.path = path;
79-
this.parent = parent;
80-
this.type = assertNotNull(type, () -> "you must provide a graphql type");
81-
this.arguments = arguments;
82-
this.fieldContainer = fieldsContainer;
68+
private final Supplier<ImmutableMapWithNullValues<String, Object>> arguments;
69+
70+
private ExecutionStepInfo(Builder builder) {
71+
this.fieldDefinition = builder.fieldDefinition;
72+
this.field = builder.field;
73+
this.path = builder.path;
74+
this.parent = builder.parentInfo;
75+
this.type = assertNotNull(builder.type, () -> "you must provide a graphql type");
76+
this.arguments = builder.arguments;
77+
this.fieldContainer = builder.fieldContainer;
8378
}
8479

8580
/**
8681
* @return the GraphQLObjectType defining the {@link #getFieldDefinition()}
87-
* @deprecated use {@link #getObjectType()} instead as it is named better
82+
*
8883
* @see ExecutionStepInfo#getObjectType()
84+
* @deprecated use {@link #getObjectType()} instead as it is named better
8985
*/
9086
@Deprecated
9187
public GraphQLObjectType getFieldContainer() {
@@ -165,19 +161,20 @@ public boolean isListType() {
165161
* @return the resolved arguments that have been passed to this field
166162
*/
167163
public Map<String, Object> getArguments() {
168-
return arguments;
164+
return arguments.get();
169165
}
170166

171167
/**
172168
* Returns the named argument
173169
*
174170
* @param name the name of the argument
175171
* @param <T> you decide what type it is
172+
*
176173
* @return the named argument or null if its not present
177174
*/
178175
@SuppressWarnings("unchecked")
179176
public <T> T getArgument(String name) {
180-
return (T) arguments.get(name);
177+
return (T) getArguments().get(name);
181178
}
182179

183180
/**
@@ -201,14 +198,15 @@ public boolean hasParent() {
201198
* after type resolution has occurred
202199
*
203200
* @param newType the new type to be
201+
*
204202
* @return a new type info with the same
205203
*/
206204
public ExecutionStepInfo changeTypeWithPreservedNonNull(GraphQLOutputType newType) {
207205
assertTrue(!GraphQLTypeUtil.isNonNull(newType), () -> "newType can't be non null");
208206
if (isNonNullType()) {
209-
return new ExecutionStepInfo(GraphQLNonNull.nonNull(newType), fieldDefinition, field, path, this.parent, arguments, this.fieldContainer);
207+
return newExecutionStepInfo(this).type(GraphQLNonNull.nonNull(newType)).build();
210208
} else {
211-
return new ExecutionStepInfo(newType, fieldDefinition, field, path, this.parent, arguments, this.fieldContainer);
209+
return newExecutionStepInfo(this).type(newType).build();
212210
}
213211
}
214212

@@ -257,13 +255,13 @@ public static class Builder {
257255
GraphQLObjectType fieldContainer;
258256
MergedField field;
259257
ResultPath path;
260-
ImmutableMapWithNullValues<String, Object> arguments;
258+
Supplier<ImmutableMapWithNullValues<String, Object>> arguments;
261259

262260
/**
263261
* @see ExecutionStepInfo#newExecutionStepInfo()
264262
*/
265263
private Builder() {
266-
arguments = ImmutableMapWithNullValues.emptyMap();
264+
arguments = ImmutableMapWithNullValues::emptyMap;
267265
}
268266

269267
private Builder(ExecutionStepInfo existing) {
@@ -273,7 +271,7 @@ private Builder(ExecutionStepInfo existing) {
273271
this.fieldContainer = existing.fieldContainer;
274272
this.field = existing.field;
275273
this.path = existing.path;
276-
this.arguments = ImmutableMapWithNullValues.copyOf(existing.getArguments());
274+
this.arguments = existing.arguments;
277275
}
278276

279277
public Builder type(GraphQLOutputType type) {
@@ -301,8 +299,11 @@ public Builder path(ResultPath resultPath) {
301299
return this;
302300
}
303301

304-
public Builder arguments(Map<String, Object> arguments) {
305-
this.arguments = arguments == null ? ImmutableMapWithNullValues.emptyMap() : ImmutableMapWithNullValues.copyOf(arguments);
302+
public Builder arguments(Supplier<Map<String, Object>> arguments) {
303+
this.arguments = () -> {
304+
Map<String, Object> map = arguments.get();
305+
return map == null ? ImmutableMapWithNullValues.emptyMap() : ImmutableMapWithNullValues.copyOf(map);
306+
};
306307
return this;
307308
}
308309

@@ -312,7 +313,7 @@ public Builder fieldContainer(GraphQLObjectType fieldContainer) {
312313
}
313314

314315
public ExecutionStepInfo build() {
315-
return new ExecutionStepInfo(type, fieldDefinition, field, path, parentInfo, arguments, fieldContainer);
316+
return new ExecutionStepInfo(this);
316317
}
317318
}
318319
}

src/main/java/graphql/execution/ExecutionStepInfoFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import graphql.schema.GraphQLList;
99
import graphql.schema.GraphQLObjectType;
1010
import graphql.schema.GraphQLOutputType;
11+
import graphql.util.FpKit;
1112

1213
import java.util.List;
1314
import java.util.Map;
15+
import java.util.function.Supplier;
1416

1517
@Internal
1618
public class ExecutionStepInfoFactory {
@@ -25,7 +27,7 @@ public ExecutionStepInfo newExecutionStepInfoForSubField(ExecutionContext execut
2527
GraphQLOutputType fieldType = fieldDefinition.getType();
2628
List<Argument> fieldArgs = mergedField.getArguments();
2729
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
28-
Map<String, Object> argumentValues = valuesResolver.getArgumentValues(codeRegistry, fieldDefinition.getArguments(), fieldArgs, executionContext.getVariables());
30+
Supplier<Map<String, Object>> argumentValues = FpKit.intraThreadMemoize(() -> valuesResolver.getArgumentValues(codeRegistry, fieldDefinition.getArguments(), fieldArgs, executionContext.getVariables()));
2931

3032
ResultPath newPath = parentInfo.getPath().segment(mergedField.getResultKey());
3133

src/main/java/graphql/execution/ExecutionStrategy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -810,14 +810,14 @@ protected ExecutionStepInfo createExecutionStepInfo(ExecutionContext executionCo
810810
ExecutionStepInfo parentStepInfo = parameters.getExecutionStepInfo();
811811
GraphQLOutputType fieldType = fieldDefinition.getType();
812812
List<GraphQLArgument> fieldArgDefs = fieldDefinition.getArguments();
813-
Map<String, Object> argumentValues = Collections.emptyMap();
813+
Supplier<Map<String, Object>> argumentValues = Collections::emptyMap;
814814
//
815815
// no need to create args at all if there are none on the field def
816816
//
817817
if (!fieldArgDefs.isEmpty()) {
818818
List<Argument> fieldArgs = field.getArguments();
819819
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
820-
argumentValues = valuesResolver.getArgumentValues(codeRegistry, fieldArgDefs, fieldArgs, executionContext.getVariables());
820+
argumentValues = FpKit.intraThreadMemoize(() -> valuesResolver.getArgumentValues(codeRegistry, fieldArgDefs, fieldArgs, executionContext.getVariables()));
821821
}
822822

823823

src/main/java/graphql/execution/ResolveType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public GraphQLObjectType resolveType(ExecutionContext executionContext, MergedFi
2727
.field(field)
2828
.fieldType(fieldType)
2929
.value(source)
30-
.argumentValues(executionStepInfo.getArguments())
30+
.argumentValues(executionStepInfo::getArguments)
3131
.selectionSet(fieldSelectionSet)
3232
.context(executionContext.getContext())
3333
.graphQLContext(executionContext.getGraphQLContext())

src/main/java/graphql/execution/TypeResolutionParameters.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import graphql.schema.GraphQLType;
1010

1111
import java.util.Map;
12+
import java.util.function.Supplier;
1213

1314
/**
1415
* This class is a classic builder style one that SHOULD have been on have been on {@link TypeResolutionEnvironment}
@@ -20,7 +21,7 @@ public class TypeResolutionParameters {
2021
private final MergedField field;
2122
private final GraphQLType fieldType;
2223
private final Object value;
23-
private final ImmutableMapWithNullValues<String, Object> argumentValues;
24+
private final Supplier<ImmutableMapWithNullValues<String, Object>> argumentValues;
2425
private final GraphQLSchema schema;
2526
private final Object context;
2627
private final Object localContext;
@@ -52,7 +53,7 @@ public Object getValue() {
5253
}
5354

5455
public Map<String, Object> getArgumentValues() {
55-
return argumentValues;
56+
return argumentValues.get();
5657
}
5758

5859
public GraphQLSchema getSchema() {
@@ -90,7 +91,7 @@ public static class Builder {
9091
private MergedField field;
9192
private GraphQLType fieldType;
9293
private Object value;
93-
private ImmutableMapWithNullValues<String, Object> argumentValues;
94+
private Supplier<ImmutableMapWithNullValues<String, Object>> argumentValues;
9495
private GraphQLSchema schema;
9596
private Object context;
9697
private GraphQLContext graphQLContext;
@@ -112,8 +113,8 @@ public Builder value(Object value) {
112113
return this;
113114
}
114115

115-
public Builder argumentValues(Map<String, Object> argumentValues) {
116-
this.argumentValues = ImmutableMapWithNullValues.copyOf(argumentValues);
116+
public Builder argumentValues(Supplier<Map<String, Object>> argumentValues) {
117+
this.argumentValues = () -> ImmutableMapWithNullValues.copyOf(argumentValues.get());
117118
return this;
118119
}
119120

src/test/groovy/graphql/TypeResolutionEnvironmentTest.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class TypeResolutionEnvironmentTest extends Specification {
4747

4848
def environment = TypeResolutionParameters.newParameters()
4949
.value("source")
50-
.argumentValues([a: "b"])
50+
.argumentValues(() -> [a: "b"])
5151
.field(mergedField(new Field("field")))
5252
.fieldType(interfaceType)
5353
.schema(schema)
@@ -117,7 +117,7 @@ class TypeResolutionEnvironmentTest extends Specification {
117117
when:
118118
def environmentFooBar = TypeResolutionParameters.newParameters()
119119
.value("source")
120-
.argumentValues([:])
120+
.argumentValues(() -> [:])
121121
.field(mergedField(new Field("field")))
122122
.fieldType(interfaceType)
123123
.schema(schema)
@@ -133,7 +133,7 @@ class TypeResolutionEnvironmentTest extends Specification {
133133
when:
134134
def environmentFooImpl = TypeResolutionParameters.newParameters()
135135
.value("source")
136-
.argumentValues([:])
136+
.argumentValues(() -> [:])
137137
.field(mergedField(new Field("field")))
138138
.fieldType(interfaceType)
139139
.schema(schema)

0 commit comments

Comments
 (0)