Skip to content

Commit f1fe6fd

Browse files
authored
Make ITargetHolder methods non-generic to avoid costly lookup at runtime (#9168)
* Make ITargetHolder methods non-generic to avoid costly lookup at runtime * Make ITargetHolder methods non-generic to avoid costly lookup at runtime
1 parent fa26804 commit f1fe6fd

20 files changed

+187
-131
lines changed

src/Orleans.CodeGenerator/InvokableGenerator.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,16 +286,21 @@ private MemberDeclarationSyntax GenerateSetTargetMethod(
286286
var holderParameter = holder.Identifier;
287287

288288
var containingInterface = methodDescription.ContainingInterface;
289+
var targetType = containingInterface.ToTypeSyntax();
289290
var isExtension = methodDescription.Key.ProxyBase.IsExtension;
290-
var getTarget = InvocationExpression(
291+
var (name, args) = isExtension switch
292+
{
293+
true => ("GetComponent", SingletonSeparatedList(Argument(TypeOfExpression(targetType)))),
294+
_ => ("GetTarget", SeparatedList<ArgumentSyntax>())
295+
};
296+
var getTarget = CastExpression(
297+
targetType,
298+
InvocationExpression(
291299
MemberAccessExpression(
292300
SyntaxKind.SimpleMemberAccessExpression,
293301
holder,
294-
GenericName(isExtension ? "GetComponent" : "GetTarget")
295-
.WithTypeArgumentList(
296-
TypeArgumentList(
297-
SingletonSeparatedList(containingInterface.ToTypeSyntax())))))
298-
.WithArgumentList(ArgumentList());
302+
IdentifierName(name)),
303+
ArgumentList(args)));
299304

300305
var member =
301306
MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), "SetTarget")
@@ -322,7 +327,7 @@ private MemberDeclarationSyntax GenerateSetTargetMethod(
322327
}
323328
}
324329

325-
private MemberDeclarationSyntax GenerateGetTargetMethod(TargetFieldDescription targetField)
330+
private static MethodDeclarationSyntax GenerateGetTargetMethod(TargetFieldDescription targetField)
326331
{
327332
return MethodDeclaration(PredefinedType(Token(SyntaxKind.ObjectKeyword)), "GetTarget")
328333
.WithParameterList(ParameterList())

src/Orleans.Core/Runtime/ClientGrainContext.cs

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
using System;
1+
#nullable enable
22
using System.Collections.Concurrent;
3-
using System.Collections.Generic;
4-
using System.Threading;
5-
using System.Threading.Tasks;
3+
using System.Diagnostics.CodeAnalysis;
64
using Microsoft.Extensions.DependencyInjection;
7-
using Orleans.Runtime;
85

96
namespace Orleans
107
{
11-
internal class ClientGrainContext : IGrainContext, IGrainExtensionBinder, IGrainContextAccessor
8+
internal sealed class ClientGrainContext : IGrainContext, IGrainExtensionBinder, IGrainContextAccessor
129
{
13-
private readonly object _lockObj = new object();
10+
private readonly object _lockObj = new();
1411
private readonly ConcurrentDictionary<Type, (object Implementation, IAddressable Reference)> _extensions = new();
1512
private readonly ConcurrentDictionary<Type, object> _components = new();
1613
private readonly OutsideRuntimeClient _runtimeClient;
17-
private GrainReference _grainReference;
14+
private GrainReference? _grainReference;
1815

1916
public ClientGrainContext(OutsideRuntimeClient runtimeClient)
2017
{
@@ -25,56 +22,48 @@ public ClientGrainContext(OutsideRuntimeClient runtimeClient)
2522

2623
public GrainId GrainId => _runtimeClient.CurrentActivationAddress.GrainId;
2724

28-
public object GrainInstance => null;
25+
public object? GrainInstance => null;
2926

3027
public ActivationId ActivationId => _runtimeClient.CurrentActivationAddress.ActivationId;
3128

3229
public GrainAddress Address => _runtimeClient.CurrentActivationAddress;
3330

3431
public IServiceProvider ActivationServices => _runtimeClient.ServiceProvider;
3532

36-
public IGrainLifecycle ObservableLifecycle => null;
33+
public IGrainLifecycle ObservableLifecycle => throw new NotSupportedException();
3734

3835
IGrainContext IGrainContextAccessor.GrainContext => this;
3936

40-
public IWorkItemScheduler Scheduler => throw new NotImplementedException();
37+
public IWorkItemScheduler Scheduler => throw new NotSupportedException();
4138

42-
public bool IsExemptFromCollection => true;
39+
public bool Equals(IGrainContext? other) => ReferenceEquals(this, other);
4340

44-
public PlacementStrategy PlacementStrategy => ClientObserversPlacement.Instance;
45-
46-
public bool Equals(IGrainContext other) => ReferenceEquals(this, other);
47-
48-
public TComponent GetComponent<TComponent>() where TComponent : class
41+
public object? GetComponent(Type componentType)
4942
{
50-
if (this is TComponent component) return component;
51-
if (_components.TryGetValue(typeof(TComponent), out var result))
43+
if (componentType.IsAssignableFrom(GetType())) return this;
44+
if (_components.TryGetValue(componentType, out var result))
5245
{
53-
return (TComponent)result;
46+
return result;
5447
}
55-
else if (typeof(TComponent) == typeof(PlacementStrategy))
48+
else if (componentType == typeof(PlacementStrategy))
5649
{
57-
return (TComponent)(object)ClientObserversPlacement.Instance;
50+
return ClientObserversPlacement.Instance;
5851
}
5952

6053
lock (_lockObj)
6154
{
62-
if (ActivationServices.GetService<TComponent>() is { } activatedComponent)
55+
if (ActivationServices.GetService(componentType) is { } activatedComponent)
6356
{
64-
return (TComponent)_components.GetOrAdd(typeof(TComponent), activatedComponent);
57+
return _components.GetOrAdd(componentType, activatedComponent);
6558
}
6659
}
6760

6861
return default;
6962
}
7063

71-
public TTarget GetTarget<TTarget>() where TTarget : class
72-
{
73-
if (this is TTarget target) return target;
74-
return default;
75-
}
64+
public object? GetTarget() => this;
7665

77-
public void SetComponent<TComponent>(TComponent instance) where TComponent : class
66+
public void SetComponent<TComponent>(TComponent? instance) where TComponent : class
7867
{
7968
if (this is TComponent)
8069
{
@@ -137,7 +126,7 @@ private bool TryGetExtension<TExtension, TExtensionInterface>(out (TExtension, T
137126
return false;
138127
}
139128

140-
private bool TryGetExtension<TExtensionInterface>(out TExtensionInterface result)
129+
private bool TryGetExtension<TExtensionInterface>([NotNullWhen(true)] out TExtensionInterface? result)
141130
where TExtensionInterface : IGrainExtension
142131
{
143132
if (_extensions.TryGetValue(typeof(TExtensionInterface), out var existing))
@@ -178,12 +167,9 @@ public TExtensionInterface GetExtension<TExtensionInterface>()
178167
}
179168
}
180169

181-
public void ReceiveMessage(object message)
182-
{
183-
throw new NotImplementedException();
184-
}
170+
public void ReceiveMessage(object message) => throw new NotSupportedException();
185171

186-
public void Activate(Dictionary<string, object> requestContext, CancellationToken cancellationToken) { }
172+
public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }
187173
public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }
188174

189175
public void Rehydrate(IRehydrationContext context)
@@ -192,11 +178,11 @@ public void Rehydrate(IRehydrationContext context)
192178
(context as IDisposable)?.Dispose();
193179
}
194180

195-
public void Migrate(Dictionary<string, object> requestContext, CancellationToken cancellationToken)
181+
public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)
196182
{
197183
// Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.
198184
}
199185

200186
public Task Deactivated => Task.CompletedTask;
201187
}
202-
}
188+
}

src/Orleans.Core/Runtime/InvokableObjectManager.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,21 @@ void IGrainContext.SetComponent<TComponent>(TComponent? value) where TComponent
132132
_manager.rootGrainContext.SetComponent(value);
133133
}
134134

135-
public TComponent? GetComponent<TComponent>() where TComponent : class
135+
public object? GetComponent(Type componentType)
136136
{
137-
if (this.LocalObject.Target is TComponent component)
137+
if (componentType.IsAssignableFrom(this.LocalObject.Target?.GetType()))
138138
{
139-
return component;
139+
return LocalObject.Target;
140140
}
141-
else if (this is TComponent thisAsComponent)
141+
else if (componentType.IsAssignableFrom(GetType()))
142142
{
143-
return thisAsComponent;
143+
return this;
144144
}
145145

146-
return _manager.rootGrainContext.GetComponent<TComponent>();
146+
return _manager.rootGrainContext.GetComponent(componentType);
147147
}
148148

149-
public TTarget? GetTarget<TTarget>() where TTarget : class => this.LocalObject.Target as TTarget;
149+
public object? GetTarget() => this.LocalObject.Target;
150150

151151
bool IEquatable<IGrainContext>.Equals(IGrainContext? other) => ReferenceEquals(this, other);
152152

src/Orleans.Runtime/Activation/ConfigureDefaultGrainActivator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using Orleans.Metadata;
33

44
namespace Orleans.Runtime
@@ -16,7 +16,7 @@ public ConfigureDefaultGrainActivator(GrainClassMap grainClassMap, IServiceProvi
1616

1717
public void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared)
1818
{
19-
if (shared.GetComponent<IGrainActivator>() is object) return;
19+
if (shared.GetComponent<IGrainActivator>() is not null) return;
2020

2121
if (!_grainClassMap.TryGetGrainClass(grainType, out var grainClass))
2222
{
@@ -27,4 +27,4 @@ public void Configure(GrainType grainType, GrainProperties properties, GrainType
2727
shared.SetComponent<IGrainActivator>(instanceActivator);
2828
}
2929
}
30-
}
30+
}

src/Orleans.Runtime/Catalog/ActivationData.cs

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -256,62 +256,69 @@ private DehydrationContextHolder? DehydrationContext
256256

257257
public TimeSpan CollectionAgeLimit => _shared.CollectionAgeLimit;
258258

259-
public TTarget? GetTarget<TTarget>() where TTarget : class => (TTarget?)GrainInstance;
259+
public object? GetTarget() => GrainInstance;
260260

261-
TComponent? ITargetHolder.GetComponent<TComponent>() where TComponent : class
261+
object? ITargetHolder.GetComponent(Type componentType)
262262
{
263-
var result = GetComponent<TComponent>();
264-
if (result is null && typeof(IGrainExtension).IsAssignableFrom(typeof(TComponent)))
263+
var result = GetComponent(componentType);
264+
if (result is null && typeof(IGrainExtension).IsAssignableFrom(componentType))
265265
{
266-
var implementation = ActivationServices.GetKeyedService<IGrainExtension>(typeof(TComponent));
267-
if (implementation is not TComponent typedResult)
266+
var implementation = ActivationServices.GetKeyedService<IGrainExtension>(componentType);
267+
if (implementation is not { } typedResult)
268268
{
269-
throw new GrainExtensionNotInstalledException($"No extension of type {typeof(TComponent)} is installed on this instance and no implementations are registered for automated install");
269+
throw new GrainExtensionNotInstalledException($"No extension of type {componentType} is installed on this instance and no implementations are registered for automated install");
270270
}
271271

272-
SetComponent(typedResult);
272+
SetComponent(componentType, typedResult);
273273
result = typedResult;
274274
}
275275

276276
return result;
277277
}
278278

279-
public TComponent? GetComponent<TComponent>() where TComponent : class
279+
public TComponent? GetComponent<TComponent>() where TComponent : class => GetComponent(typeof(TComponent)) as TComponent;
280+
281+
public object? GetComponent(Type componentType)
280282
{
281-
TComponent? result = default;
282-
if (GrainInstance is TComponent grainResult)
283+
object? result;
284+
if (componentType.IsAssignableFrom(GrainInstance?.GetType()))
283285
{
284-
result = grainResult;
286+
result = GrainInstance;
285287
}
286-
else if (this is TComponent contextResult)
288+
else if (componentType.IsAssignableFrom(GetType()))
287289
{
288-
result = contextResult;
290+
result = this;
289291
}
290-
else if (_extras is { } components && components.TryGetValue(typeof(TComponent), out var resultObj))
292+
else if (_extras is { } components && components.TryGetValue(componentType, out var resultObj))
291293
{
292-
result = (TComponent)resultObj;
294+
result = resultObj;
293295
}
294-
else if (_shared.GetComponent<TComponent>() is { } sharedComponent)
296+
else if (_shared.GetComponent(componentType) is { } sharedComponent)
295297
{
296298
result = sharedComponent;
297299
}
298-
else if (ActivationServices.GetService<TComponent>() is { } component)
300+
else if (ActivationServices.GetService(componentType) is { } component)
299301
{
300-
SetComponent(component);
302+
SetComponent(componentType, component);
301303
result = component;
302304
}
305+
else
306+
{
307+
result = null;
308+
}
303309

304310
return result;
305311
}
306312

307-
public void SetComponent<TComponent>(TComponent? instance) where TComponent : class
313+
public void SetComponent<TComponent>(TComponent? instance) where TComponent : class => SetComponent(typeof(TComponent), instance);
314+
315+
public void SetComponent(Type componentType, object? instance)
308316
{
309-
if (GrainInstance is TComponent)
317+
if (componentType.IsAssignableFrom(GrainInstance?.GetType()))
310318
{
311319
throw new ArgumentException("Cannot override a component which is implemented by this grain");
312320
}
313-
314-
if (this is TComponent)
321+
else if (componentType.IsAssignableFrom(GetType()))
315322
{
316323
throw new ArgumentException("Cannot override a component which is implemented by this grain context");
317324
}
@@ -320,12 +327,12 @@ public void SetComponent<TComponent>(TComponent? instance) where TComponent : cl
320327
{
321328
if (instance == null)
322329
{
323-
_extras?.Remove(typeof(TComponent));
330+
_extras?.Remove(componentType);
324331
return;
325332
}
326333

327334
_extras ??= new();
328-
_extras[typeof(TComponent)] = instance;
335+
_extras[componentType] = instance;
329336
}
330337
}
331338

@@ -776,7 +783,7 @@ public async ValueTask DisposeAsync()
776783

777784
try
778785
{
779-
var activator = _shared.GetComponent<IGrainActivator>();
786+
var activator = _shared.GetComponent(typeof(IGrainActivator)) as IGrainActivator;
780787
if (activator != null && GrainInstance is { } instance)
781788
{
782789
await activator.DisposeInstance(this, instance);

src/Orleans.Runtime/Catalog/GrainTypeSharedContext.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@ private static TimeSpan GetCollectionAgeLimit(GrainType grainType, Type grainCla
118118
return (TComponent?)resultObj;
119119
}
120120

121+
/// <summary>
122+
/// Gets a component.
123+
/// </summary>
124+
/// <param name="componentType">The type of the component.</param>
125+
/// <returns>The component with the specified type.</returns>
126+
public object? GetComponent(Type componentType)
127+
{
128+
if (componentType == typeof(PlacementStrategy))
129+
{
130+
return PlacementStrategy;
131+
}
132+
133+
if (componentType == typeof(ILogger))
134+
{
135+
return Logger;
136+
}
137+
138+
if (_components is null) return default;
139+
_components.TryGetValue(componentType, out var resultObj);
140+
return resultObj;
141+
}
142+
121143
/// <summary>
122144
/// Registers a component.
123145
/// </summary>

src/Orleans.Runtime/Catalog/StatelessWorkerGrainContext.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ private void EnqueueWorkItem(WorkItemType type, object state)
118118

119119
public bool Equals([AllowNull] IGrainContext other) => other is not null && ActivationId.Equals(other.ActivationId);
120120

121-
public TComponent? GetComponent<TComponent>() where TComponent : class => this switch
121+
public object? GetComponent(Type componentType)
122122
{
123-
TComponent contextResult => contextResult,
124-
_ => _shared.GetComponent<TComponent>()
125-
};
123+
if (componentType.IsAssignableFrom(GetType())) return this;
124+
return _shared.GetComponent(componentType);
125+
}
126126

127127
public void SetComponent<TComponent>(TComponent? instance) where TComponent : class
128128
{
@@ -134,7 +134,7 @@ public void SetComponent<TComponent>(TComponent? instance) where TComponent : cl
134134
_shared.SetComponent(instance);
135135
}
136136

137-
public TTarget GetTarget<TTarget>() where TTarget : class => throw new NotImplementedException();
137+
public object? GetTarget() => throw new NotImplementedException();
138138

139139
private async Task RunMessageLoop()
140140
{

0 commit comments

Comments
 (0)