Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ITargetHolder methods non-generic to avoid costly lookup at runtime #9168

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/Orleans.CodeGenerator/InvokableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,16 +282,21 @@ private MemberDeclarationSyntax GenerateSetTargetMethod(
var holderParameter = holder.Identifier;

var containingInterface = methodDescription.ContainingInterface;
var targetType = containingInterface.ToTypeSyntax();
var isExtension = methodDescription.Key.ProxyBase.IsExtension;
var getTarget = InvocationExpression(
var (name, args) = isExtension switch
{
true => ("GetComponent", SingletonSeparatedList(Argument(TypeOfExpression(targetType)))),
_ => ("GetTarget", SeparatedList<ArgumentSyntax>())
};
var getTarget = CastExpression(
targetType,
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
holder,
GenericName(isExtension ? "GetComponent" : "GetTarget")
.WithTypeArgumentList(
TypeArgumentList(
SingletonSeparatedList(containingInterface.ToTypeSyntax())))))
.WithArgumentList(ArgumentList());
IdentifierName(name)),
ArgumentList(args)));

var body =
AssignmentExpression(
Expand All @@ -305,7 +310,7 @@ private MemberDeclarationSyntax GenerateSetTargetMethod(
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)));
}

private MemberDeclarationSyntax GenerateGetTargetMethod(TargetFieldDescription targetField)
private static MethodDeclarationSyntax GenerateGetTargetMethod(TargetFieldDescription targetField)
{
return MethodDeclaration(PredefinedType(Token(SyntaxKind.ObjectKeyword)), "GetTarget")
.WithParameterList(ParameterList())
Expand Down
24 changes: 11 additions & 13 deletions src/Orleans.Core/Runtime/ClientGrainContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -45,34 +46,31 @@ public ClientGrainContext(OutsideRuntimeClient runtimeClient)

public bool Equals(IGrainContext other) => ReferenceEquals(this, other);

public TComponent GetComponent<TComponent>() where TComponent : class
public TComponent GetComponent<TComponent>() where TComponent : class => (TComponent)GetComponent(typeof(TComponent));
public object GetComponent(Type componentType)
{
if (this is TComponent component) return component;
if (_components.TryGetValue(typeof(TComponent), out var result))
if (componentType.IsAssignableFrom(GetType())) return this;
if (_components.TryGetValue(componentType, out var result))
{
return (TComponent)result;
return result;
}
else if (typeof(TComponent) == typeof(PlacementStrategy))
else if (componentType == typeof(PlacementStrategy))
{
return (TComponent)(object)ClientObserversPlacement.Instance;
return ClientObserversPlacement.Instance;
}

lock (_lockObj)
{
if (ActivationServices.GetService<TComponent>() is { } activatedComponent)
if (ActivationServices.GetService(componentType) is { } activatedComponent)
{
return (TComponent)_components.GetOrAdd(typeof(TComponent), activatedComponent);
return _components.GetOrAdd(componentType, activatedComponent);
}
}

return default;
}

public TTarget GetTarget<TTarget>() where TTarget : class
{
if (this is TTarget target) return target;
return default;
}
public object GetTarget() => this;

public void SetComponent<TComponent>(TComponent instance) where TComponent : class
{
Expand Down
11 changes: 6 additions & 5 deletions src/Orleans.Core/Runtime/InvokableObjectManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,18 @@ void IGrainContext.SetComponent<TComponent>(TComponent value) where TComponent :
_manager.rootGrainContext.SetComponent(value);
}

public TComponent GetComponent<TComponent>() where TComponent : class
public TComponent GetComponent<TComponent>() where TComponent : class => (TComponent)GetComponent(typeof(TComponent));
public object GetComponent(Type componentType)
{
if (this.LocalObject.Target is TComponent component)
if (componentType.IsAssignableFrom(this.LocalObject.Target?.GetType()))
{
return component;
return LocalObject.Target;
}

return _manager.rootGrainContext.GetComponent<TComponent>();
return _manager.rootGrainContext.GetComponent(componentType);
}

public TTarget GetTarget<TTarget>() where TTarget : class => (TTarget)this.LocalObject.Target;
public object GetTarget() => this.LocalObject.Target;

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

Expand Down
37 changes: 19 additions & 18 deletions src/Orleans.Runtime/Catalog/ActivationData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,17 @@ private DehydrationContextHolder? DehydrationContext

public TimeSpan CollectionAgeLimit => _shared.CollectionAgeLimit;

public TTarget? GetTarget<TTarget>() where TTarget : class => (TTarget?)GrainInstance;
public object? GetTarget() => GrainInstance;

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

SetComponent(typedResult);
Expand All @@ -246,29 +246,30 @@ private DehydrationContextHolder? DehydrationContext
return result;
}

public TComponent? GetComponent<TComponent>() where TComponent : class
public TComponent? GetComponent<TComponent>() where TComponent : class => (TComponent?)GetComponent(typeof(TComponent));
public object? GetComponent(Type componentType)
{
TComponent? result;
if (GrainInstance is TComponent grainResult)
object? result;
if (componentType.IsAssignableFrom(GrainInstance?.GetType()))
{
result = grainResult;
result = GrainInstance;
}
else if (this is TComponent contextResult)
else if (componentType.IsAssignableFrom(GetType()))
{
result = contextResult;
result = this;
}
else if (_extras is { } components && components.TryGetValue(typeof(TComponent), out var resultObj))
else if (_extras is { } components && components.TryGetValue(componentType, out var resultObj))
{
result = (TComponent)resultObj;
result = resultObj;
}
else if (ActivationServices.GetService<TComponent>() is { } component)
else if (ActivationServices.GetService(componentType) is { } component)
{
SetComponent(component);
result = component;
}
else
{
result = _shared.GetComponent<TComponent>();
result = _shared.GetComponent(componentType);
}

return result;
Expand Down Expand Up @@ -814,7 +815,7 @@ public async ValueTask DisposeAsync()

try
{
var activator = _shared.GetComponent<IGrainActivator>();
var activator = _shared.GetComponent(typeof(IGrainActivator)) as IGrainActivator;
if (activator != null && GrainInstance is { } instance)
{
await activator.DisposeInstance(this, instance);
Expand Down
18 changes: 11 additions & 7 deletions src/Orleans.Runtime/Catalog/GrainTypeSharedContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Orleans.Runtime;
public class GrainTypeSharedContext
{
private readonly IServiceProvider _serviceProvider;
private readonly Dictionary<Type, object> _components = new();
private readonly Dictionary<Type, object> _components = [];
private InternalGrainRuntime? _internalGrainRuntime;

public GrainTypeSharedContext(
Expand Down Expand Up @@ -98,23 +98,27 @@ private static TimeSpan GetCollectionAgeLimit(GrainType grainType, Type grainCla
/// <summary>
/// Gets a component.
/// </summary>
/// <typeparam name="TComponent">The type specified in the corresponding <see cref="SetComponent{TComponent}"/> call.</typeparam>
public TComponent? GetComponent<TComponent>()
public TComponent? GetComponent<TComponent>() where TComponent : class => GetComponent(typeof(TComponent)) as TComponent;

/// <summary>
/// Gets a component.
/// </summary>
public object? GetComponent(Type componentType)
{
if (typeof(TComponent) == typeof(PlacementStrategy) && PlacementStrategy is TComponent component)
if (componentType == typeof(PlacementStrategy) && PlacementStrategy is { } component)
{
return component;
}

if (_components is null) return default;
_components.TryGetValue(typeof(TComponent), out var resultObj);
return (TComponent?)resultObj;
_components.TryGetValue(componentType, out var resultObj);
return resultObj;
}

/// <summary>
/// Registers a component.
/// </summary>
/// <typeparam name="TComponent">The type which can be used as a key to <see cref="GetComponent{TComponent}"/>.</typeparam>
/// <typeparam name="TComponent">The type which can be used as a key to <see cref="GetComponent"/>.</typeparam>
public void SetComponent<TComponent>(TComponent? instance)
{
if (instance == null)
Expand Down
10 changes: 5 additions & 5 deletions src/Orleans.Runtime/Catalog/StatelessWorkerGrainContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ private void EnqueueWorkItem(WorkItemType type, object state)

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

public TComponent? GetComponent<TComponent>() where TComponent : class => this switch
public object? GetComponent(Type componentType)
{
TComponent contextResult => contextResult,
_ => _shared.GetComponent<TComponent>()
};
if (componentType.IsAssignableFrom(GetType())) return this;
return _shared.GetComponent(componentType);
}

public void SetComponent<TComponent>(TComponent? instance) where TComponent : class
{
Expand All @@ -116,7 +116,7 @@ public void SetComponent<TComponent>(TComponent? instance) where TComponent : cl
_shared.SetComponent(instance);
}

public TTarget GetTarget<TTarget>() where TTarget : class => throw new NotImplementedException();
public object GetTarget() => throw new NotImplementedException();

private async Task RunMessageLoop()
{
Expand Down
21 changes: 11 additions & 10 deletions src/Orleans.Runtime/Core/HostedClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,24 @@ public void DeleteObjectReference(IAddressable obj)
}
}

public TComponent? GetComponent<TComponent>() where TComponent : class
public TComponent? GetComponent<TComponent>() where TComponent : class => (TComponent?)GetComponent(typeof(TComponent));
public object? GetComponent(Type componentType)
{
if (this is TComponent component) return component;
if (_components.TryGetValue(typeof(TComponent), out var result))
if (componentType.IsAssignableFrom(GetType())) return this;
if (_components.TryGetValue(componentType, out var result))
{
return (TComponent)result;
return result;
}
else if (typeof(TComponent) == typeof(PlacementStrategy))
else if (componentType == typeof(PlacementStrategy))
{
return (TComponent)(object)ClientObserversPlacement.Instance;
return ClientObserversPlacement.Instance;
}

lock (lockObj)
{
if (ActivationServices.GetService<TComponent>() is { } activatedComponent)
if (ActivationServices.GetService(componentType) is { } activatedComponent)
{
return (TComponent)_components.GetOrAdd(typeof(TComponent), activatedComponent);
return _components.GetOrAdd(componentType, activatedComponent);
}
}

Expand Down Expand Up @@ -204,7 +205,7 @@ public void ReceiveMessage(object message)

if (msg.Direction == Message.Directions.Response)
{
// Requests are made through the runtime client, so deliver responses to the rutnime client so that the request callback can be executed.
// Requests are made through the runtime client, so deliver responses to the runtime client so that the request callback can be executed.
this.runtimeClient.ReceiveResponse(msg);
}
else
Expand Down Expand Up @@ -383,7 +384,7 @@ public TExtensionInterface GetExtension<TExtensionInterface>()
}
}

public TTarget GetTarget<TTarget>() where TTarget : class => throw new NotImplementedException();
public object? GetTarget() => throw new NotImplementedException();
public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }
public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }
public Task Deactivated => Task.CompletedTask;
Expand Down
38 changes: 9 additions & 29 deletions src/Orleans.Runtime/Core/SystemTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,21 @@ internal SystemTarget(SystemTargetGrainId grainId, SiloAddress silo, ILoggerFact
/// <summary>
/// Gets the component with the specified type.
/// </summary>
/// <typeparam name="TComponent">The component type.</typeparam>
/// <returns>The component with the specified type.</returns>
public TComponent GetComponent<TComponent>()
public object GetComponent(Type componentType)
{
TComponent result;
if (this is TComponent instanceResult)
object result;
if (componentType.IsAssignableFrom(GetType()))
{
result = instanceResult;
result = this;
}
else if (_components.TryGetValue(typeof(TComponent), out var resultObj))
else if (_components.TryGetValue(componentType, out var resultObj))
{
result = (TComponent)resultObj;
result = resultObj;
}
else if (typeof(TComponent) == typeof(PlacementStrategy))
else if (componentType == typeof(PlacementStrategy))
{
result = (TComponent)(object)SystemTargetPlacementStrategy.Instance;
result = SystemTargetPlacementStrategy.Instance;
}
else
{
Expand Down Expand Up @@ -224,25 +223,6 @@ bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, Re
return (implementation, reference);
}

/// <inheritdoc/>
TComponent ITargetHolder.GetComponent<TComponent>()
{
var result = this.GetComponent<TComponent>();
if (result is null && typeof(IGrainExtension).IsAssignableFrom(typeof(TComponent)))
{
var implementation = this.ActivationServices.GetKeyedService<IGrainExtension>(typeof(TComponent));
if (implementation is not TComponent typedResult)
{
throw new GrainExtensionNotInstalledException($"No extension of type {typeof(TComponent)} is installed on this instance and no implementations are registered for automated install");
}

this.SetComponent<TComponent>(typedResult);
result = typedResult;
}

return result;
}

/// <inheritdoc/>
public TExtensionInterface GetExtension<TExtensionInterface>()
where TExtensionInterface : class, IGrainExtension
Expand Down Expand Up @@ -284,7 +264,7 @@ public void ReceiveMessage(object message)
}

/// <inheritdoc/>
public TTarget GetTarget<TTarget>() where TTarget : class => (TTarget)(object)this;
public object GetTarget()=> this;

/// <inheritdoc/>
public void Activate(Dictionary<string, object> requestContext, CancellationToken cancellationToken) { }
Expand Down
Loading
Loading