Skip to content

Conversation

@bbakerman
Copy link
Member

@bbakerman bbakerman commented Sep 10, 2022

The idea here is to make the object creation for DataFetchers even lighter.

This is basically here for PropertyDataFetcher to implement since it ONLY needs the source really to get property values from.

The premise is that we avoid allocating all the objects that go into a DataFetchingEnvironment for simple property fetches

Benchmark Mode Cnt Score Error Units LightWeightPropertyFetchingBenchMark.benchMarkHeavyWeightFetchingThroughput thrpt 25 22.599 ± 1.062 ops/s LightWeightPropertyFetchingBenchMark.benchMarkLightWeightFetchingThroughput thrpt 25 23.303 ± 1.040 ops/s LightWeightPropertyFetchingBenchMark.benchMarkHeavyWeightFetchingAvgTime avgt 25 44.772 ± 2.599 ms/op LightWeightPropertyFetchingBenchMark.benchMarkLightWeightFetchingAvgTime avgt 25 43.132 ± 2.479 ms/op 

So for this benchmark - this IS slightly faster - the more simple property fetches there are, the more savings to be made

This benchmark biases towards property fetches on purpose

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Copy link
Member Author

Choose a reason for hiding this comment

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

never used

executionContext.getGraphQLSchema(),
executionContext.getCoercedVariables().toMap(),
executionContext.getGraphQLContext(),
executionContext.getLocale());
Copy link
Member Author

@bbakerman bbakerman Sep 10, 2022

Choose a reason for hiding this comment

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

These all move down into the supplier of the DataFetchingEnv - they are ONLY needed for it so UNTIL we ask for the DFE - none of this code is run

Copy link
Member Author

Choose a reason for hiding this comment

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

Its a bit hard to see - open the fill view to see it

fetchCtx.onCompleted(result, exception);
if (exception != null) {
return handleFetchingException(executionContext, environment, exception);
return handleFetchingException(executionContext, dataFetchingEnvironment.get(), exception);
Copy link
Member Author

Choose a reason for hiding this comment

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

we ONLY use the DFE here if we have an exception which is least trodden path

default T get(GraphQLFieldDefinition fieldDefinition, Object sourceObject, Supplier<DataFetchingEnvironment> environmentSupplier) throws Exception {
return get(environmentSupplier.get());
}

Copy link
Member Author

Choose a reason for hiding this comment

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

old DataFetchers will be called via delegating back to the old method. Those DFS that implement this method will be called direct

}
return fetchedValue;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

moved the fetch call into its own method to reduce method complexity

@PublicApi
public class InstrumentationFieldFetchParameters extends InstrumentationFieldParameters {
private final DataFetchingEnvironment environment;
private final Supplier<DataFetchingEnvironment> environment;
Copy link
Member Author

Choose a reason for hiding this comment

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

needs to be a supplier until they ask for it

@jord1e
Copy link
Contributor

jord1e commented Sep 16, 2022

this wouldn't disable any validation right, or would it?

If we take away looking at solely PropertyDataFetcher, would there be an advantage/disadvantage to introducing a isLeightWeight() method to DataFetcher instead of globally applying it via Backdoor? Would that even be useful?

It could be true by default for PropertyDataFetcher, if we know that we will need the DataFetchingEnvironment two method calls (including getSource(), it will be called later anyway) will be avoided at least (including the moving of fieldDef and the supplier onto the stack).

This would maybe confusing because we have two datafetcher methods and one will not be used when isLeightWeight is false. We could offer some default impls to check for it and throw an exception on invalid method calls in combination with invalid isLightWeight for the datafetcher.

grafik

@bbakerman
Copy link
Member Author

@jord1e

this wouldn't disable any validation right, or would it?

No - this does the same amount of processing as usual. The saving here is that we don't create the full DFE when calling a DataFetcher that uses the new method signature.

If we take away looking at solely PropertyDataFetcher, would there be an advantage/disadvantage to introducing a isLeightWeight() method to DataFetcher instead of globally applying it via Backdoor?

The Backdoor is not meant to be permanent code. I created it PURELY so I could have a switch to use in a JMH benchmark. This allows me to test code apth X and then code path Y

If this PR got reworked to be accepted then this Backdoor goes away and we would call in via the new method and the old get(DFE env) method would be called via defaulting in the interface. Code (like PropertyDataFetcher) that is aware of the new signature could avoid the extra methed call by implementing the new signature

@jord1e
Copy link
Contributor

jord1e commented Sep 19, 2022

Cool, almost exactly what I thought then 🙂. a ms is a ms

@bbakerman bbakerman changed the title WIP - DO NOT MERGE - lightweight data fetchers Lightweight data fetchers Oct 18, 2022
@bbakerman bbakerman added this to the 20.0 milestone Oct 18, 2022
Supplier<ExecutableNormalizedField> normalizedFieldSupplier = getNormalizedField(executionContext, parameters, executionStepInfo);
Supplier<DataFetchingEnvironment> dataFetchingEnvironment = FpKit.intraThreadMemoize(() -> {

// DataFetchingFieldSelectionSet and QueryDirectives is a supplier of sorts - eg a lazy pattern
Copy link
Member Author

Choose a reason for hiding this comment

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

DFE creation is now one big supplier

* and the related field will have a value of {@code null} in the result.
*/
T get(GraphQLFieldDefinition fieldDefinition, Object sourceObject, Supplier<DataFetchingEnvironment> environmentSupplier) throws Exception;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Added a new interface to keep Andi happy and to better delineate what the data fetcher does. Is it light or heavy?

Its MUST be a DataFetcher however because the CodeRegistry requires a DataFetcher when registered

…ty_fetching # Conflicts: #	src/main/java/graphql/schema/PropertyFetchingImpl.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants