Skip to content

Commit 77913da

Browse files
authored
Reworked the fusion execution state management. (#6325)
1 parent 2ea2bed commit 77913da

File tree

14 files changed

+189
-92
lines changed

14 files changed

+189
-92
lines changed

.editorconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ indent_size = 2
77
indent_style = space
88
insert_final_newline = true
99
trim_trailing_whitespace = true
10-
rulers = 100
10+
rulers = 120
1111

1212
[*.md]
1313
trim_trailing_whitespace = false
@@ -100,4 +100,4 @@ csharp_preserve_single_line_blocks = true
100100
dotnet_style_require_accessibility_modifiers = always
101101

102102
# Public API
103-
dotnet_diagnostic.RS0016.severity = warning
103+
dotnet_diagnostic.RS0016.severity = warning

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"**/*.code-search": true,
66
"**/PublicAPI*.txt": true
77
},
8-
"editor.rulers": [100],
8+
"editor.rulers": [120],
99
"files.trimTrailingWhitespace": true,
1010
"files.associations": {
1111
"*.*proj": "xml",

src/HotChocolate/ApolloFederation/src/ApolloFederation/FederationTypeInterceptor.cs

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,39 @@ namespace HotChocolate.ApolloFederation;
2020
internal sealed class FederationTypeInterceptor : TypeInterceptor
2121
{
2222
private static readonly object _empty = new();
23+
2324
private static readonly MethodInfo _matches =
2425
typeof(ReferenceResolverHelper)
2526
.GetMethod(
2627
nameof(ReferenceResolverHelper.Matches),
2728
BindingFlags.Static | BindingFlags.Public)!;
29+
2830
private static readonly MethodInfo _execute =
2931
typeof(ReferenceResolverHelper)
3032
.GetMethod(
3133
nameof(ReferenceResolverHelper.ExecuteAsync),
3234
BindingFlags.Static | BindingFlags.Public)!;
35+
3336
private static readonly MethodInfo _invalid =
3437
typeof(ReferenceResolverHelper)
3538
.GetMethod(
3639
nameof(ReferenceResolverHelper.Invalid),
3740
BindingFlags.Static | BindingFlags.Public)!;
41+
3842
private readonly List<ObjectType> _entityTypes = new();
43+
private IDescriptorContext _context = default!;
44+
private ITypeInspector _typeInspector = default!;
45+
46+
internal override void InitializeContext(
47+
IDescriptorContext context,
48+
TypeInitializer typeInitializer,
49+
TypeRegistry typeRegistry,
50+
TypeLookup typeLookup,
51+
TypeReferenceResolver typeReferenceResolver)
52+
{
53+
_context = context;
54+
_typeInspector = context.TypeInspector;
55+
}
3956

4057
public override void OnAfterInitialize(
4158
ITypeDiscoveryContext discoveryContext,
@@ -46,8 +63,7 @@ public override void OnAfterInitialize(
4663
{
4764
ApplyMethodLevelReferenceResolvers(
4865
objectType,
49-
objectTypeDefinition,
50-
discoveryContext);
66+
objectTypeDefinition);
5167

5268
AddToUnionIfHasTypeLevelKeyDirective(
5369
objectType,
@@ -147,49 +163,47 @@ private void AddServiceTypeToQueryType(
147163
definition is ObjectTypeDefinition objectTypeDefinition)
148164
{
149165
var serviceFieldDescriptor = ObjectFieldDescriptor.New(
150-
completionContext.DescriptorContext,
166+
_context,
151167
WellKnownFieldNames.Service);
152168
serviceFieldDescriptor
153169
.Type<NonNullType<ServiceType>>()
154170
.Resolve(_empty);
155171
objectTypeDefinition.Fields.Add(serviceFieldDescriptor.CreateDefinition());
156172

157173
var entitiesFieldDescriptor = ObjectFieldDescriptor.New(
158-
completionContext.DescriptorContext,
174+
_context,
159175
WellKnownFieldNames.Entities);
160176
entitiesFieldDescriptor
161177
.Type<NonNullType<ListType<EntityType>>>()
162178
.Argument(
163179
WellKnownArgumentNames.Representations,
164180
descriptor => descriptor.Type<NonNullType<ListType<NonNullType<AnyType>>>>())
165-
.Resolve(c => EntitiesResolver.ResolveAsync(
166-
c.Schema,
167-
c.ArgumentValue<IReadOnlyList<Representation>>(
168-
WellKnownArgumentNames.Representations),
169-
c
170-
));
181+
.Resolve(
182+
c => EntitiesResolver.ResolveAsync(
183+
c.Schema,
184+
c.ArgumentValue<IReadOnlyList<Representation>>(
185+
WellKnownArgumentNames.Representations),
186+
c
187+
));
171188
objectTypeDefinition.Fields.Add(entitiesFieldDescriptor.CreateDefinition());
172189
}
173190
}
174191

175192
private void ApplyMethodLevelReferenceResolvers(
176193
ObjectType objectType,
177-
ObjectTypeDefinition objectTypeDefinition,
178-
ITypeDiscoveryContext discoveryContext)
194+
ObjectTypeDefinition objectTypeDefinition)
179195
{
180196
if (objectType.RuntimeType != typeof(object))
181197
{
182-
var descriptorContext = discoveryContext.DescriptorContext;
183-
var typeInspector = discoveryContext.TypeInspector;
184-
var descriptor = ObjectTypeDescriptor.From(descriptorContext, objectTypeDefinition);
198+
var descriptor = ObjectTypeDescriptor.From(_context, objectTypeDefinition);
185199

186200
foreach (var possibleReferenceResolver in
187201
objectType.RuntimeType.GetMethods(BindingFlags.Static | BindingFlags.Public))
188202
{
189203
if (possibleReferenceResolver.IsDefined(typeof(ReferenceResolverAttribute)))
190204
{
191-
typeInspector.ApplyAttributes(
192-
descriptorContext,
205+
_typeInspector.ApplyAttributes(
206+
_context,
193207
descriptor,
194208
possibleReferenceResolver);
195209
}
@@ -204,7 +218,7 @@ private void AddToUnionIfHasTypeLevelKeyDirective(
204218
ObjectTypeDefinition objectTypeDefinition)
205219
{
206220
if (objectTypeDefinition.Directives.Any(
207-
d => d.Value is DirectiveNode { Name.Value: WellKnownTypeNames.Key }) ||
221+
d => d.Value is DirectiveNode { Name.Value: WellKnownTypeNames.Key }) ||
208222
objectTypeDefinition.Fields.Any(f => f.ContextData.ContainsKey(WellKnownTypeNames.Key)))
209223
{
210224
_entityTypes.Add(objectType);
@@ -284,4 +298,4 @@ private static void AddKeyDirective(
284298
objectTypeDefinition.Directives.Add(
285299
new DirectiveDefinition(directiveNode));
286300
}
287-
}
301+
}

src/HotChocolate/Fusion/src/Core/DependencyInjection/GatewayConfigurationFileObserver.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ private sealed class FileConfigurationSession : IDisposable
3030

3131
public FileConfigurationSession(IObserver<GatewayConfiguration> observer, string fileName)
3232
{
33+
var fullPath = Path.GetFullPath(fileName);
34+
var directory = Path.GetDirectoryName(fullPath);
35+
3336
_observer = observer;
34-
_fileName = fileName;
37+
_fileName = fullPath;
3538

3639
BeginLoadConfig();
3740

38-
var fullPath = Path.GetFullPath(fileName);
39-
var directory = Path.GetDirectoryName(fullPath);
40-
4141
if (directory is null)
4242
{
4343
throw new FileNotFoundException(

src/HotChocolate/Fusion/src/Core/Execution/ExecutionState.cs

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
13
using System.Diagnostics.CodeAnalysis;
24
using System.Runtime.CompilerServices;
35
using System.Runtime.InteropServices;
6+
using System.Threading;
47
using HotChocolate.Execution.Processing;
8+
using static HotChocolate.Fusion.FusionResources;
59

610
namespace HotChocolate.Fusion.Execution;
711

812
internal sealed class ExecutionState
913
{
10-
private readonly Dictionary<ISelectionSet, List<WorkItem>> _map = new();
14+
private readonly Dictionary<ISelectionSet, List<SelectionSetState>> _map = new();
1115
private readonly HashSet<ISelectionSet> _immutable = new();
1216

1317
public bool ContainsState(ISelectionSet selectionSet)
@@ -61,7 +65,7 @@ public bool ContainsState(ISelectionSet[] selectionSets)
6165

6266
public bool TryGetState(
6367
ISelectionSet selectionSet,
64-
[NotNullWhen(true)] out IReadOnlyList<WorkItem>? values)
68+
[NotNullWhen(true)] out IReadOnlyList<SelectionSetState>? values)
6569
{
6670
var taken = false;
6771
Monitor.Enter(_map, ref taken);
@@ -97,24 +101,33 @@ public bool TryGetState(
97101
}
98102
}
99103

100-
public void RegisterState(WorkItem value)
104+
public void TryRegisterState(
105+
ISelectionSet selectionSet,
106+
ObjectResult result,
107+
IReadOnlyList<string> exportKeys,
108+
SelectionData parentData)
101109
{
102110
var taken = false;
103-
List<WorkItem>? values;
111+
List<SelectionSetState>? states;
112+
SelectionSetState? state;
104113
Monitor.Enter(_map, ref taken);
105114

106115
try
107116
{
108-
if (_immutable.Contains(value.SelectionSet))
117+
if (_immutable.Contains(selectionSet))
109118
{
110-
throw new InvalidOperationException(
111-
$"The state for the selection set `{value.SelectionSet.Id}` is immutable.");
119+
return;
112120
}
113-
114-
if (!_map.TryGetValue(value.SelectionSet, out values))
121+
122+
state = new SelectionSetState(selectionSet, result, exportKeys)
115123
{
116-
var temp = new List<WorkItem> { value };
117-
_map.Add(value.SelectionSet, temp);
124+
SelectionSetData = { [0] = parentData }
125+
};
126+
127+
if (!_map.TryGetValue(state.SelectionSet, out states))
128+
{
129+
var temp = new List<SelectionSetState> { state };
130+
_map.Add(state.SelectionSet, temp);
118131
}
119132
}
120133
finally
@@ -125,23 +138,60 @@ public void RegisterState(WorkItem value)
125138
}
126139
}
127140

128-
if (values is not null)
141+
AddState(states, state);
142+
}
143+
144+
public void RegisterState(SelectionSetState state)
145+
{
146+
var taken = false;
147+
List<SelectionSetState>? states;
148+
Monitor.Enter(_map, ref taken);
149+
150+
try
129151
{
130-
taken = false;
131-
Monitor.Enter(values, ref taken);
152+
if (_immutable.Contains(state.SelectionSet))
153+
{
154+
throw new InvalidOperationException(
155+
string.Format(ExecutionState_RegisterState_StateImmutable, state.SelectionSet.Id));
156+
}
132157

133-
try
158+
if (!_map.TryGetValue(state.SelectionSet, out states))
134159
{
135-
values.Add(value);
160+
var temp = new List<SelectionSetState> { state };
161+
_map.Add(state.SelectionSet, temp);
136162
}
137-
finally
163+
}
164+
finally
165+
{
166+
if (taken)
138167
{
139-
if (taken)
140-
{
141-
Monitor.Exit(values);
142-
}
168+
Monitor.Exit(_map);
143169
}
144170
}
171+
172+
AddState(states, state);
145173
}
146-
}
174+
175+
private static void AddState(List<SelectionSetState>? states, SelectionSetState state)
176+
{
177+
if (states is null)
178+
{
179+
return;
180+
}
181+
182+
var taken = false;
183+
Monitor.Enter(states, ref taken);
147184

185+
try
186+
{
187+
states.Add(state);
188+
}
189+
finally
190+
{
191+
if (taken)
192+
{
193+
Monitor.Exit(states);
194+
}
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)