Skip to content

Commit fdb5ca3

Browse files
committed
gnhf #5: Bypassed Builder pattern in ExecutionStepInfoFactory.createExecutionStepInfo and added single-field fast path in executeObject's sync path to eliminate ~30M unnecessary object allocations per 10M-element list execution.
1 parent d3bbf75 commit fdb5ca3

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,20 @@ public static ExecutionStepInfo.Builder newExecutionStepInfo(ExecutionStepInfo e
278278
return new Builder(existing);
279279
}
280280

281+
/**
282+
* Direct construction without Builder overhead - for internal hot path use only.
283+
*/
284+
@Internal
285+
static ExecutionStepInfo newExecutionStepInfoDirect(GraphQLOutputType type,
286+
ResultPath path,
287+
ExecutionStepInfo parent,
288+
MergedField field,
289+
GraphQLFieldDefinition fieldDefinition,
290+
GraphQLObjectType fieldContainer,
291+
Supplier<ImmutableMapWithNullValues<String, Object>> arguments) {
292+
return new ExecutionStepInfo(type, path, parent, field, fieldDefinition, fieldContainer, arguments);
293+
}
294+
281295
public static class Builder {
282296
GraphQLOutputType type;
283297
ExecutionStepInfo parentInfo;

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

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
import java.util.Map;
1919
import java.util.function.Supplier;
2020

21-
import static graphql.execution.ExecutionStepInfo.newExecutionStepInfo;
22-
2321
@Internal
2422
@NullMarked
2523
public class ExecutionStepInfoFactory {
@@ -56,16 +54,15 @@ public ExecutionStepInfo createExecutionStepInfo(ExecutionContext executionConte
5654
argumentValues = getArgumentValues(executionContext, fieldArgDefs, field.getArguments());
5755
}
5856

59-
60-
return newExecutionStepInfo()
61-
.type(fieldType)
62-
.fieldDefinition(fieldDefinition)
63-
.fieldContainer(fieldContainer)
64-
.field(field)
65-
.path(parameters.getPath())
66-
.parentInfo(parentStepInfo)
67-
.arguments(argumentValues)
68-
.build();
57+
// Direct construction bypasses Builder allocation
58+
return ExecutionStepInfo.newExecutionStepInfoDirect(
59+
fieldType,
60+
parameters.getPath(),
61+
parentStepInfo,
62+
field,
63+
fieldDefinition,
64+
fieldContainer,
65+
argumentValues);
6966
}
7067

7168
@NonNull

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,23 @@ protected Object executeObject(ExecutionContext executionContext, ExecutionStrat
250250
} else {
251251
List<FieldValueInfo> completeValueInfos = (List<FieldValueInfo>) fieldValueInfosResult;
252252

253-
Async.CombinedBuilder<Object> resultFutures = fieldValuesCombinedBuilder(completeValueInfos);
254253
dataLoaderDispatcherStrategy.executeObjectOnFieldValuesInfo(completeValueInfos, parameters);
255254
resolveObjectCtx.onFieldValuesInfo(completeValueInfos);
256255

256+
// Fast path: single sync field value - avoid CombinedBuilder overhead
257+
if (completeValueInfos.size() == 1) {
258+
FieldValueInfo singleFvi = completeValueInfos.get(0);
259+
Object fieldValue = singleFvi.getFieldValueObject();
260+
if (!(fieldValue instanceof CompletableFuture)) {
261+
Map<String, Object> fieldValueMap = executionContext.getResponseMapFactory()
262+
.createInsertionOrdered(fieldsExecutedOnInitialResult, Collections.singletonList(fieldValue));
263+
resolveObjectCtx.onCompleted(fieldValueMap, null);
264+
return fieldValueMap;
265+
}
266+
}
267+
268+
Async.CombinedBuilder<Object> resultFutures = fieldValuesCombinedBuilder(completeValueInfos);
269+
257270
Object completedValuesObject = resultFutures.awaitPolymorphic();
258271
if (completedValuesObject instanceof CompletableFuture) {
259272
// Semi-async path - allocate CF infrastructure only when needed

0 commit comments

Comments
 (0)