From a9b3958732df62f09b14afcc9f1e389da4e4f206 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 17:45:25 -0700 Subject: [PATCH 1/7] Pool generated IInvokable request objects Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ActivatorGenerator.cs | 67 ++++++++- src/Orleans.CodeGenerator/CodeGenerator.cs | 2 +- .../InvokableGenerator.cs | 96 +++++++++++- src/Orleans.CodeGenerator/LibraryTypes.cs | 2 + src/Orleans.CodeGenerator/ProxyGenerator.cs | 138 ++++++++++++++++-- .../Runtime/GrainReference.cs | 65 +++++++++ src/Orleans.Core/Messaging/Message.cs | 46 +++++- src/Orleans.Core/Messaging/MessageFactory.cs | 2 + src/Orleans.Core/Networking/Connection.cs | 10 ++ src/Orleans.Core/Runtime/CallbackData.cs | 12 +- .../Hosting/ServiceCollectionExtensions.cs | 3 + .../Invocation/Pools/ConcurrentObjectPool.cs | 21 ++- .../Invocation/Pools/InvokablePool.cs | 57 +++++++- 13 files changed, 487 insertions(+), 34 deletions(-) diff --git a/src/Orleans.CodeGenerator/ActivatorGenerator.cs b/src/Orleans.CodeGenerator/ActivatorGenerator.cs index 7acb8d8757d..326fe467dae 100644 --- a/src/Orleans.CodeGenerator/ActivatorGenerator.cs +++ b/src/Orleans.CodeGenerator/ActivatorGenerator.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using System.Collections.Generic; +using System.Linq; namespace Orleans.CodeGenerator { @@ -15,6 +16,7 @@ private struct ConstructorArgument public TypeSyntax Type { get; set; } public string FieldName { get; set; } public string ParameterName { get; set; } + public bool IsPool { get; set; } } public ActivatorGenerator(CodeGenerator codeGenerator) @@ -34,7 +36,9 @@ public ClassDeclarationSyntax GenerateActivator(ISerializableTypeDescription typ { foreach (var arg in parameters) { - orderedFields.Add(new ConstructorArgument { Type = arg, FieldName = $"_arg{index}", ParameterName = $"arg{index}" }); + // Detect if this is an InvokablePool parameter + var isPool = arg is GenericNameSyntax gns && gns.Identifier.Text == "InvokablePool"; + orderedFields.Add(new ConstructorArgument { Type = arg, FieldName = $"_arg{index}", ParameterName = $"arg{index}", IsPool = isPool }); index++; } } @@ -80,11 +84,23 @@ private ConstructorDeclarationSyntax GenerateConstructor( { parameters.Add(Parameter(field.ParameterName.ToIdentifier()).WithType(field.Type)); - body.Add(ExpressionStatement( - AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - field.FieldName.ToIdentifierName(), - Unwrapped(field.ParameterName.ToIdentifierName())))); + // Pool fields are not wrapped services, assign directly + if (field.IsPool) + { + body.Add(ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + field.FieldName.ToIdentifierName(), + field.ParameterName.ToIdentifierName()))); + } + else + { + body.Add(ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + field.FieldName.ToIdentifierName(), + Unwrapped(field.ParameterName.ToIdentifierName())))); + } } var constructorDeclaration = ConstructorDeclaration(simpleClassName) @@ -104,6 +120,45 @@ static ExpressionSyntax Unwrapped(ExpressionSyntax expr) private MemberDeclarationSyntax GenerateCreateMethod(ISerializableTypeDescription type, List orderedFields) { + // Check if this is a poolable invokable (has InvokablePool as first constructor argument) + var poolField = orderedFields.FirstOrDefault(f => f.IsPool); + + if (poolField.IsPool) + { + // Generate: _pool.TryGet(out var item) ? item : new T(_pool, ...otherArgs) + var argList = new List(); + foreach (var field in orderedFields) + { + argList.Add(Argument(field.FieldName.ToIdentifierName())); + } + + var newExpression = ObjectCreationExpression(type.TypeSyntax) + .WithArgumentList(ArgumentList(SeparatedList(argList))); + + // _pool.TryGet(out var item) + var tryGetCall = InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + poolField.FieldName.ToIdentifierName(), + IdentifierName("TryGet")), + ArgumentList(SingletonSeparatedList( + Argument(DeclarationExpression( + IdentifierName("var"), + SingleVariableDesignation(Identifier("item")))) + .WithRefKindKeyword(Token(SyntaxKind.OutKeyword))))); + + // Conditional: tryGet ? item : new T(...) + var conditionalExpression = ConditionalExpression( + tryGetCall, + IdentifierName("item"), + newExpression); + + return MethodDeclaration(type.TypeSyntax, "Create") + .WithExpressionBody(ArrowExpressionClause(conditionalExpression)) + .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) + .AddModifiers(Token(SyntaxKind.PublicKeyword)); + } + ExpressionSyntax createObject; if (type.ActivatorConstructorParameters is { Count: > 0 }) { diff --git a/src/Orleans.CodeGenerator/CodeGenerator.cs b/src/Orleans.CodeGenerator/CodeGenerator.cs index 93091f3839b..f99934194df 100644 --- a/src/Orleans.CodeGenerator/CodeGenerator.cs +++ b/src/Orleans.CodeGenerator/CodeGenerator.cs @@ -383,7 +383,7 @@ bool ShouldIncludePrimaryConstructorParameters(INamedTypeSymbol t) })); } - var usings = List(new[] { UsingDirective(ParseName("global::Orleans.Serialization.Codecs")), UsingDirective(ParseName("global::Orleans.Serialization.GeneratedCodeHelpers")) }); + var usings = List(new[] { UsingDirective(ParseName("global::Orleans.Serialization.Codecs")), UsingDirective(ParseName("global::Orleans.Serialization.GeneratedCodeHelpers")), UsingDirective(ParseName("global::Orleans.Serialization.Invocation")) }); var namespaces = new List(_namespacedMembers.Count); foreach (var pair in _namespacedMembers) { diff --git a/src/Orleans.CodeGenerator/InvokableGenerator.cs b/src/Orleans.CodeGenerator/InvokableGenerator.cs index cd4db8407bf..ffb3f7b2a7e 100644 --- a/src/Orleans.CodeGenerator/InvokableGenerator.cs +++ b/src/Orleans.CodeGenerator/InvokableGenerator.cs @@ -33,8 +33,12 @@ public GeneratedInvokableDescription Generate(InvokableMethodDescription invokab var baseClassType = GetBaseClassType(invokableMethodInfo); var fieldDescriptions = GetFieldDescriptions(invokableMethodInfo); - var fields = GetFieldDeclarations(invokableMethodInfo, fieldDescriptions); - var (ctor, ctorArgs) = GenerateConstructor(generatedClassName, invokableMethodInfo, baseClassType); + + // Create the invokable type syntax for use in field declarations and constructor + var invokableTypeSyntax = CreateInvokableTypeSyntax(generatedClassName, invokableMethodInfo); + + var fields = GetFieldDeclarations(invokableMethodInfo, fieldDescriptions, invokableTypeSyntax); + var (ctor, ctorArgs) = GenerateConstructor(generatedClassName, invokableMethodInfo, baseClassType, fieldDescriptions, invokableTypeSyntax); var accessibility = GetAccessibility(method); var compoundTypeAliases = GetCompoundTypeAliasAttributeArguments(invokableMethodInfo, invokableMethodInfo.Key); @@ -588,6 +592,8 @@ private MemberDeclarationSyntax GenerateDisposeMethod( INamedTypeSymbol baseClassType) { var body = new List(); + PoolFieldDescription poolField = null; + foreach (var field in fields) { if (field is CancellationTokenSourceFieldDescription ctsField) @@ -602,6 +608,11 @@ private MemberDeclarationSyntax GenerateDisposeMethod( MemberBindingExpression(IdentifierName("Dispose")))))); } + if (field is PoolFieldDescription pf) + { + poolField = pf; + } + if (field.IsInstanceField) { body.Add( @@ -621,6 +632,19 @@ private MemberDeclarationSyntax GenerateDisposeMethod( body.Add(ExpressionStatement(InvocationExpression(BaseExpression().Member("Dispose")).WithArgumentList(ArgumentList()))); } + // C# _pool.Return(this); - return to pool at the very end + if (poolField != null) + { + body.Add( + ExpressionStatement( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(poolField.FieldName), + IdentifierName("Return")), + ArgumentList(SingletonSeparatedList(Argument(ThisExpression())))))); + } + return MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), "Dispose") .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))) .WithBody(Block(body)); @@ -698,9 +722,28 @@ public static string GetSimpleClassName(InvokableMethodDescription method) return $"Invokable_{method.ContainingInterface.Name}_{proxyKey}_{method.GeneratedMethodId}{typeArgs}"; } + private static TypeSyntax CreateInvokableTypeSyntax(string generatedClassName, InvokableMethodDescription method) + { + if (method.AllTypeParameters.Count > 0) + { + // Generic invokable: ClassName + var typeArguments = method.AllTypeParameters.Select(p => + (TypeSyntax)IdentifierName(method.TypeParameterSubstitutions[p.Parameter])); + return GenericName( + Identifier(generatedClassName), + TypeArgumentList(SeparatedList(typeArguments))); + } + else + { + // Non-generic invokable: ClassName + return IdentifierName(generatedClassName); + } + } + private MemberDeclarationSyntax[] GetFieldDeclarations( InvokableMethodDescription method, - List fieldDescriptions) + List fieldDescriptions, + TypeSyntax invokableTypeSyntax) { return fieldDescriptions.Select(GetFieldDeclaration).ToArray(); @@ -728,6 +771,18 @@ MemberDeclarationSyntax GetFieldDeclaration(InvokerFieldDescription description) })))))))) .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword)); } + else if (description is PoolFieldDescription) + { + // Pool field: InvokablePool + var poolType = GenericName( + Identifier("InvokablePool"), + TypeArgumentList(SingletonSeparatedList(invokableTypeSyntax))); + field = FieldDeclaration( + VariableDeclaration( + poolType, + SingletonSeparatedList(VariableDeclarator(description.FieldName)))) + .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword)); + } else { field = FieldDeclaration( @@ -758,7 +813,9 @@ private ExpressionSyntax GetTypesArray(InvokableMethodDescription method, IEnume private (ConstructorDeclarationSyntax Constructor, List ConstructorArguments) GenerateConstructor( string simpleClassName, InvokableMethodDescription method, - INamedTypeSymbol baseClassType) + INamedTypeSymbol baseClassType, + List fieldDescriptions, + TypeSyntax invokableTypeSyntax) { var parameters = new List(); @@ -766,6 +823,23 @@ private ExpressionSyntax GetTypesArray(InvokableMethodDescription method, IEnume List constructorArgumentTypes = new(); List baseConstructorArguments = new(); + + // For non-generic methods, add pool parameter first + var poolField = fieldDescriptions.OfType().FirstOrDefault(); + if (poolField != null) + { + var poolType = GenericName( + Identifier("InvokablePool"), + TypeArgumentList(SingletonSeparatedList(invokableTypeSyntax))); + constructorArgumentTypes.Add(poolType); + parameters.Add(Parameter(Identifier("pool")).WithType(poolType)); + body.Add(ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(poolField.FieldName), + IdentifierName("pool")))); + } + foreach (var constructor in baseClassType.GetAllMembers()) { if (constructor.MethodKind != MethodKind.Constructor || constructor.DeclaredAccessibility == Accessibility.Private || constructor.IsImplicitlyDeclared) @@ -831,6 +905,12 @@ private List GetFieldDescriptions(InvokableMethodDescri fields.Add(new CancellationTokenSourceFieldDescription(LibraryTypes)); } + // Add pool field for non-generic methods (generic methods can't use pooling) + if (method.MethodTypeParameters.Count == 0) + { + fields.Add(new PoolFieldDescription(LibraryTypes)); + } + return fields; } @@ -940,5 +1020,13 @@ public MethodInfoFieldDescription(ITypeSymbol fieldType, string fieldName) : bas public override bool IsSerializable => false; public override bool IsInstanceField => false; } + + internal sealed class PoolFieldDescription : InvokerFieldDescription + { + public PoolFieldDescription(LibraryTypes libraryTypes) : base(libraryTypes.InvokablePool_1, "_pool") { } + + public override bool IsSerializable => false; + public override bool IsInstanceField => false; // Assigned via constructor, not reset on dispose + } } } diff --git a/src/Orleans.CodeGenerator/LibraryTypes.cs b/src/Orleans.CodeGenerator/LibraryTypes.cs index 9906407935c..f2be8a93399 100644 --- a/src/Orleans.CodeGenerator/LibraryTypes.cs +++ b/src/Orleans.CodeGenerator/LibraryTypes.cs @@ -34,6 +34,7 @@ private LibraryTypes(Compilation compilation, CodeGeneratorOptions options) GenerateSerializerAttribute = Type("Orleans.GenerateSerializerAttribute"); SerializationCallbacksAttribute = Type("Orleans.SerializationCallbacksAttribute"); IActivator_1 = Type("Orleans.Serialization.Activators.IActivator`1"); + InvokablePool_1 = Type("Orleans.Serialization.Invocation.InvokablePool`1"); IBufferWriter = Type("System.Buffers.IBufferWriter`1"); IdAttributeType = Type(CodeGeneratorOptions.IdAttribute); ConstructorAttributeTypes = CodeGeneratorOptions.ConstructorAttributes.Select(Type).ToArray(); @@ -215,6 +216,7 @@ INamedTypeSymbol Type(string metadataName) public INamedTypeSymbol GenerateMethodSerializersAttribute { get; private set; } public INamedTypeSymbol GenerateSerializerAttribute { get; private set; } public INamedTypeSymbol IActivator_1 { get; private set; } + public INamedTypeSymbol InvokablePool_1 { get; private set; } public INamedTypeSymbol IBufferWriter { get; private set; } public INamedTypeSymbol IInvokable { get; private set; } public INamedTypeSymbol ITargetHolder { get; private set; } diff --git a/src/Orleans.CodeGenerator/ProxyGenerator.cs b/src/Orleans.CodeGenerator/ProxyGenerator.cs index d9727ceb58f..bd0efeca55f 100644 --- a/src/Orleans.CodeGenerator/ProxyGenerator.cs +++ b/src/Orleans.CodeGenerator/ProxyGenerator.cs @@ -21,6 +21,7 @@ internal class ProxyGenerator { private const string CopyContextPoolMemberName = "CopyContextPool"; private const string CodecProviderMemberName = "CodecProvider"; + private const string SharedMemberName = "Shared"; private readonly CodeGenerator _codeGenerator; public ProxyGenerator(CodeGenerator codeGenerator) @@ -36,9 +37,24 @@ public ProxyGenerator(CodeGenerator codeGenerator) var fieldDescriptions = GetFieldDescriptions(interfaceDescription); var fieldDeclarations = GetFieldDeclarations(fieldDescriptions); - var proxyMethods = CreateProxyMethods(fieldDescriptions, interfaceDescription); - var ctors = GenerateConstructors(generatedClassName, fieldDescriptions, interfaceDescription.ProxyBaseType); + // Build activator index mapping for non-generic methods that use activators + var activatorIndexMap = new Dictionary(); + var activatorIndex = 0; + foreach (var method in interfaceDescription.Methods) + { + if (method.MethodTypeParameters.Count == 0 && method.GeneratedInvokable.UseActivator) + { + activatorIndexMap[method] = activatorIndex++; + } + } + + var proxyMethods = CreateProxyMethods(fieldDescriptions, interfaceDescription, activatorIndexMap); + var activatorMembers = interfaceDescription.ProxyBaseType is not null && ProxyBaseHasActivatorMethods(interfaceDescription.ProxyBaseType) + ? Array.Empty() + : GetActivatorMembers(activatorIndexMap.Count); + + var ctors = GenerateConstructors(generatedClassName, fieldDescriptions, interfaceDescription.ProxyBaseType, interfaceDescription, activatorIndexMap); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes( @@ -47,6 +63,7 @@ public ProxyGenerator(CodeGenerator codeGenerator) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes()) .AddMembers(fieldDeclarations) + .AddMembers(activatorMembers) .AddMembers(ctors) .AddMembers(proxyMethods); @@ -61,7 +78,7 @@ public ProxyGenerator(CodeGenerator codeGenerator) public static string GetSimpleClassName(ProxyInterfaceDescription interfaceDescription) => $"Proxy_{SyntaxGeneration.Identifier.SanitizeIdentifierName(interfaceDescription.Name)}"; - + private List GetFieldDescriptions( ProxyInterfaceDescription interfaceDescription) { @@ -86,9 +103,56 @@ static MemberDeclarationSyntax GetFieldDeclaration(GeneratedFieldDescription des } } + private static bool ProxyBaseHasActivatorMethods(INamedTypeSymbol baseType) + { + return HasMethod(baseType, "EnsureActivator") && HasMethod(baseType, "GetActivator"); + + static bool HasMethod(INamedTypeSymbol type, string name) + { + for (var current = type; current is not null; current = current.BaseType) + { + if (current.GetMembers(name).OfType().Any(method => + method.DeclaredAccessibility != Accessibility.Private && method.Arity == 1 && method.Parameters.Length == 1)) + { + return true; + } + } + + return false; + } + } + + private static MemberDeclarationSyntax[] GetActivatorMembers(int activatorCount) + { + if (activatorCount == 0) + { + return Array.Empty(); + } + + return new[] + { + ParseMemberDeclaration($"private readonly object[] _activators = new object[{activatorCount}];"), + ParseMemberDeclaration( + """ + private void EnsureActivator(int index) + { + _activators[index] ??= CodecProvider.GetActivator(); + } + """), + ParseMemberDeclaration( + """ + private global::Orleans.Serialization.Activators.IActivator GetActivator(int index) + { + return (global::Orleans.Serialization.Activators.IActivator)_activators[index]; + } + """) + }; + } + private MemberDeclarationSyntax[] CreateProxyMethods( List fieldDescriptions, - ProxyInterfaceDescription interfaceDescription) + ProxyInterfaceDescription interfaceDescription, + Dictionary activatorIndexMap) { var res = new List(); foreach (var methodDescription in interfaceDescription.Methods) @@ -99,7 +163,7 @@ private MemberDeclarationSyntax[] CreateProxyMethods( MethodDeclarationSyntax CreateProxyMethod(ProxyMethodDescription methodDescription) { - var (isAsync, body) = CreateAsyncProxyMethodBody(fieldDescriptions, methodDescription); + var (isAsync, body) = CreateAsyncProxyMethodBody(fieldDescriptions, methodDescription, activatorIndexMap); var method = methodDescription.Method; var declaration = MethodDeclaration(method.ReturnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions), method.Name.EscapeIdentifier()) .AddParameterListParameters(method.Parameters.Select((p, i) => GetParameterSyntax(i, p, methodDescription.TypeParameterSubstitutions)).ToArray()) @@ -125,18 +189,42 @@ MethodDeclarationSyntax CreateProxyMethod(ProxyMethodDescription methodDescripti private (bool IsAsync, BlockSyntax body) CreateAsyncProxyMethodBody( List fieldDescriptions, - ProxyMethodDescription methodDescription) + ProxyMethodDescription methodDescription, + Dictionary activatorIndexMap) { var statements = new List(); var requestVar = IdentifierName("request"); var methodSymbol = methodDescription.Method; var invokable = methodDescription.GeneratedInvokable; - ExpressionSyntax createRequestExpr = (!invokable.IsEmptyConstructable || invokable.UseActivator) switch + + ExpressionSyntax createRequestExpr; + if (activatorIndexMap.TryGetValue(methodDescription, out var activatorIdx)) { - true => InvocationExpression(ThisExpression().Member("GetInvokable", invokable.TypeSyntax)) - .WithArgumentList(ArgumentList(SeparatedList())), - _ => ObjectCreationExpression(invokable.TypeSyntax).WithArgumentList(ArgumentList()) - }; + // Non-generic method with activator: use GetActivator(index).Create() + // C#: GetActivator(index).Create() + createRequestExpr = InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + InvocationExpression( + GenericName( + Identifier("GetActivator"), + TypeArgumentList(SingletonSeparatedList(invokable.TypeSyntax))), + ArgumentList(SingletonSeparatedList(Argument( + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(activatorIdx)))))), + IdentifierName("Create")), + ArgumentList()); + } + else if (!invokable.IsEmptyConstructable || invokable.UseActivator) + { + // Generic method or other case that needs GetInvokable + createRequestExpr = InvocationExpression(ThisExpression().Member("GetInvokable", invokable.TypeSyntax)) + .WithArgumentList(ArgumentList(SeparatedList())); + } + else + { + // Simple case: direct construction + createRequestExpr = ObjectCreationExpression(invokable.TypeSyntax).WithArgumentList(ArgumentList()); + } statements.Add( LocalDeclarationStatement( @@ -285,7 +373,9 @@ MethodDeclarationSyntax CreateProxyMethod(ProxyMethodDescription methodDescripti private MemberDeclarationSyntax[] GenerateConstructors( string simpleClassName, List fieldDescriptions, - INamedTypeSymbol baseType) + INamedTypeSymbol baseType, + ProxyInterfaceDescription interfaceDescription, + Dictionary activatorIndexMap) { if (baseType is null) { @@ -390,6 +480,30 @@ List GetBodyStatements() break; } } + + // Generate activator initialization if needed + if (activatorIndexMap.Count > 0) + { + // Call EnsureActivator(index) for each method that needs pooling + // C#: EnsureActivator(0); + // C#: EnsureActivator(1); + // ... + foreach (var kvp in activatorIndexMap.OrderBy(x => x.Value)) + { + var method = kvp.Key; + var index = kvp.Value; + var invokable = method.GeneratedInvokable; + + res.Add(ExpressionStatement( + InvocationExpression( + GenericName( + Identifier("EnsureActivator"), + TypeArgumentList(SingletonSeparatedList(invokable.TypeSyntax))), + ArgumentList(SingletonSeparatedList(Argument( + LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(index)))))))); + } + } + return res; static ExpressionSyntax Unwrapped(ExpressionSyntax expr) diff --git a/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs b/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs index fc39a9aade3..9777362c33e 100644 --- a/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs +++ b/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Orleans.Serialization.Activators; using Orleans.Serialization.Cloning; using Orleans.Serialization.Codecs; using Orleans.Serialization.Invocation; @@ -20,6 +21,9 @@ namespace Orleans.Runtime /// public class GrainReferenceShared { + private readonly object _activatorsLock = new(); + private object[] _activators = []; + public GrainReferenceShared( GrainType grainType, GrainInterfaceType grainInterfaceType, @@ -79,6 +83,52 @@ public GrainReferenceShared( /// Gets the interface version. /// public ushort InterfaceVersion { get; } + + /// + /// Ensures an activator exists at the specified index, creating it if necessary. + /// This method is thread-safe and will grow the array if needed. + /// + /// The invokable type. + /// The index of the activator in the array. + public void EnsureActivator(int index) + { + var activators = _activators; + if (activators.Length > index && activators[index] is not null) + { + return; + } + + lock (_activatorsLock) + { + activators = _activators; + if (activators.Length > index && activators[index] is not null) + { + return; + } + + // Grow array if necessary + if (activators.Length <= index) + { + var newActivators = new object[index + 1]; + Array.Copy(activators, newActivators, activators.Length); + activators = newActivators; + } + + // Create the activator + activators[index] = CodecProvider.GetActivator(); + _activators = activators; + } + } + + /// + /// Gets an activator from the cached array at the specified index. + /// Callers must ensure has been called first. + /// + /// The invokable type. + /// The index of the activator in the array. + /// The activator for the specified invokable type. + public IActivator GetActivator(int index) + => (IActivator)_activators[index]; } /// @@ -297,6 +347,21 @@ public class GrainReference : IAddressable, IEquatable, ISpanFor /// protected CodecProvider CodecProvider => _shared.CodecProvider; + /// + /// Ensures an activator exists at the specified index for the given invokable type. + /// + /// The invokable type. + /// The index of the activator in the array. + protected void EnsureActivator(int index) => _shared.EnsureActivator(index); + + /// + /// Gets an activator from the cached array at the specified index. + /// + /// The invokable type. + /// The index of the activator in the array. + /// The activator for the specified invokable type. + protected IActivator GetActivator(int index) => _shared.GetActivator(index); + /// Initializes a new instance of the class. /// /// The grain reference functionality which is shared by all grain references of a given type. diff --git a/src/Orleans.Core/Messaging/Message.cs b/src/Orleans.Core/Messaging/Message.cs index 16e7f67bc41..1d3f2a0dbbf 100644 --- a/src/Orleans.Core/Messaging/Message.cs +++ b/src/Orleans.Core/Messaging/Message.cs @@ -15,6 +15,13 @@ internal sealed class Message : ISpanFormattable [NonSerialized] private short _retryCount; + /// + /// When true, the will be disposed when this message is reset (returned to the pool). + /// This is used for pooling invokable request objects. + /// + [NonSerialized] + internal bool DisposeBodyObject; + public CoarseStopwatch _timeToExpiry; public object? BodyObject { get; set; } @@ -371,6 +378,41 @@ static bool Append(ref Span dst, ReadOnlySpan value) internal bool IsPing() => _requestContextData?.TryGetValue(RequestContext.PING_APPLICATION_HEADER, out var value) == true && value is bool isPing && isPing; + /// + /// Disposes the message body if it is marked as disposable by the message owner. + /// + internal void DisposeBody() + { + if (DisposeBodyObject) + { + (BodyObject as IDisposable)?.Dispose(); + DisposeBodyObject = false; + BodyObject = null; + } + } + + /// + /// Resets the message to its default state for reuse. + /// + internal void Reset() + { + _retryCount = 0; + _timeToExpiry = default; + DisposeBody(); + BodyObject = null; + _headers = default; + _id = default; + _requestContextData = null; + _targetSilo = null; + _targetGrain = default; + _sendingSilo = null; + _sendingGrain = default; + _interfaceVersion = 0; + _interfaceType = default; + _cacheInvalidationHeader = null; + } + + [Flags] internal enum MessageFlags : ushort { @@ -386,10 +428,10 @@ internal enum MessageFlags : ushort HasTimeToLive = 1 << 8, // Message cannot be forwarded to another activation. - IsLocalOnly = 1 << 9, + IsLocalOnly = 1 << 9, // Message must not trigger grain activation or extend an activation's lifetime. - SuppressKeepAlive = 1 << 10, + SuppressKeepAlive = 1 << 10, // The most significant bit is reserved, possibly for use to indicate more data follows. Reserved = 1 << 15, diff --git a/src/Orleans.Core/Messaging/MessageFactory.cs b/src/Orleans.Core/Messaging/MessageFactory.cs index e41bc632815..29f9a9d2d8c 100644 --- a/src/Orleans.Core/Messaging/MessageFactory.cs +++ b/src/Orleans.Core/Messaging/MessageFactory.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using Orleans.CodeGeneration; using Orleans.Serialization; +using Orleans.Serialization.Invocation; #nullable disable namespace Orleans.Runtime @@ -40,6 +41,7 @@ public Message CreateMessage(object body, InvokeMethodOptions options) IsUnordered = (options & InvokeMethodOptions.Unordered) != 0, IsAlwaysInterleave = (options & InvokeMethodOptions.AlwaysInterleave) != 0, BodyObject = body, + DisposeBodyObject = body is IInvokable, RequestContextData = RequestContextExtensions.Export(_deepCopier), }; diff --git a/src/Orleans.Core/Networking/Connection.cs b/src/Orleans.Core/Networking/Connection.cs index f2f0bc728de..cc660b0ee80 100644 --- a/src/Orleans.Core/Networking/Connection.cs +++ b/src/Orleans.Core/Networking/Connection.cs @@ -382,6 +382,16 @@ private async Task ProcessOutgoing() break; } + // Dispose one-way request bodies after they've been sent. + // Request-response bodies are disposed when the callback completes. + foreach (var msg in inflight) + { + if (msg.Direction == Message.Directions.OneWay) + { + msg.DisposeBody(); + } + } + inflight.Clear(); } } diff --git a/src/Orleans.Core/Runtime/CallbackData.cs b/src/Orleans.Core/Runtime/CallbackData.cs index 98536d69ce7..20bdb32629e 100644 --- a/src/Orleans.Core/Runtime/CallbackData.cs +++ b/src/Orleans.Core/Runtime/CallbackData.cs @@ -108,6 +108,7 @@ private void OnCancellation() OrleansCallBackDataEvent.Instance.OnCanceled(Message); context.Complete(Response.FromException(new OperationCanceledException(_cancellationTokenRegistration.Token))); _cancellationTokenRegistration.Dispose(); + this.Message.DisposeBody(); } public void OnTimeout() @@ -138,6 +139,7 @@ public void OnTimeout() var exception = new TimeoutException($"Response did not arrive on time in {timeout} for message: {msg}. {statusMessage}"); context.Complete(Response.FromException(exception)); + this.Message.DisposeBody(); } public void OnTargetSiloFail() @@ -158,6 +160,7 @@ public void OnTargetSiloFail() LogTargetSiloFail(this.shared.Logger, msg, statusMessage, Constants.TroubleshootingHelpLink); var exception = new SiloUnavailableException($"The target silo became unavailable for message: {msg}. {statusMessage}See {Constants.TroubleshootingHelpLink} for troubleshooting help."); this.context.Complete(Response.FromException(exception)); + this.Message.DisposeBody(); } public void DoCallback(Message response) @@ -174,7 +177,14 @@ public void DoCallback(Message response) _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation. - ResponseCallback(response, this.context); + try + { + ResponseCallback(response, this.context); + } + finally + { + this.Message.DisposeBody(); + } } private static void ResponseCallback(Message message, IResponseCompletionSource context) diff --git a/src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs b/src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs index 29bd92c074c..97f64d0ef69 100644 --- a/src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs +++ b/src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs @@ -65,6 +65,9 @@ public static IServiceCollection AddSerializer(this IServiceCollection services, services.TryAddSingleton(typeof(IDeepCopier<>), typeof(CopierHolder<>)); services.TryAddSingleton(typeof(IBaseCopier<>), typeof(BaseCopierHolder<>)); + // Invokable pooling + services.TryAddSingleton(typeof(Invocation.InvokablePool<>)); + // Type filtering services.AddSingleton(); diff --git a/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs b/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs index 3ef1f621c28..d4630892f0f 100644 --- a/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs +++ b/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs @@ -1,8 +1,9 @@ +#nullable enable +using System; using System.Collections.Generic; -using System.Threading; +using System.Runtime.CompilerServices; using Microsoft.Extensions.ObjectPool; -#nullable disable namespace Orleans.Serialization.Invocation { internal sealed class ConcurrentObjectPool : ConcurrentObjectPool> where T : class, new() @@ -14,17 +15,18 @@ public ConcurrentObjectPool() : base(new()) internal class ConcurrentObjectPool : ObjectPool where T : class where TPoolPolicy : IPooledObjectPolicy { - private readonly ThreadLocal> _objects = new(() => new()); - private readonly TPoolPolicy _policy; public ConcurrentObjectPool(TPoolPolicy policy) => _policy = policy; public int MaxPoolSize { get; set; } = int.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Stack GetStack() => PerThreadStack.Stack ??= new(); + public override T Get() { - var stack = _objects.Value; + var stack = GetStack(); if (stack.TryPop(out var result)) { return result; @@ -37,12 +39,19 @@ public override void Return(T obj) { if (_policy.Return(obj)) { - var stack = _objects.Value; + var stack = GetStack(); if (stack.Count < MaxPoolSize) { stack.Push(obj); } } } + + // Nested class to hold ThreadStatic field per generic type instantiation + private static class PerThreadStack + { + [ThreadStatic] + internal static Stack? Stack; + } } } diff --git a/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs b/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs index b6a76c96c4c..65abf6fb86d 100644 --- a/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs +++ b/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs @@ -1,8 +1,61 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + namespace Orleans.Serialization.Invocation { /// - /// Object pool for implementations. + /// Thread-local object pool for implementations. + /// Registered as an open generic singleton and injected into generated activators. + /// + /// The invokable type. + public sealed class InvokablePool where T : class, IInvokable + { + private const int MaxPoolSizePerThread = 128; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Stack GetStack() => PerThreadStack.Stack ??= new(); + + /// + /// Tries to get an instance from the pool. + /// + /// The pooled item, if available. + /// True if an item was retrieved from the pool; false if the pool was empty. + public bool TryGet([NotNullWhen(true)] out T? item) + { + var stack = GetStack(); + return stack.TryPop(out item); + } + + /// + /// Returns an instance to the pool. + /// + /// The item to return. + public void Return(T item) + { + var stack = GetStack(); + if (stack.Count < MaxPoolSizePerThread) + { + stack.Push(item); + } + } + + // Nested class to hold ThreadStatic field per generic type instantiation + private static class PerThreadStack + { + [ThreadStatic] + internal static Stack? Stack; + } + } + + /// + /// Static helper for pooling. /// + /// + /// This is kept for backward compatibility. New code should use directly. + /// public static class InvokablePool { /// @@ -24,4 +77,4 @@ public static class InvokablePool public static readonly ConcurrentObjectPool Pool = new(); } } -} \ No newline at end of file +} From d4040bc8b875d4f926c68efd237631194024ed1a Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 18:25:02 -0700 Subject: [PATCH 2/7] Fix invokable pooling isolation Use per-pool thread-local storage so generated invokables are not reused across service providers, and update generated code snapshots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Invocation/Pools/InvokablePool.cs | 38 +++-- ...SourceGeneratorTests.TestAlias.verified.cs | 1 + ...eGeneratorTests.TestBasicClass.verified.cs | 1 + ...tBasicClassWithAnnotatedFields.verified.cs | 1 + ...ssWithDifferentAccessModifiers.verified.cs | 1 + ....TestBasicClassWithInheritance.verified.cs | 1 + ...TestBasicClassWithoutNamespace.verified.cs | 2 + ...eGeneratorTests.TestBasicGrain.verified.cs | 42 ++++- ...GeneratorTests.TestBasicStruct.verified.cs | 1 + ...atorTests.TestClassNestedTypes.verified.cs | 1 + ...rTests.TestClassPrimitiveTypes.verified.cs | 1 + ...assPrimitiveTypesUsingFullName.verified.cs | 1 + ...s.TestClassReferenceProperties.verified.cs | 1 + ...ateMethodSerializersAnnotation.verified.cs | 43 ++++- ...thGenerateSerializerAnnotation.verified.cs | 1 + ...hInterfaceConstructorParameter.verified.cs | 1 + ...tClassWithNoPublicConstructors.verified.cs | 1 + ...hOptionalConstructorParameters.verified.cs | 1 + ...ssWithParameterizedConstructor.verified.cs | 1 + ...ActivatorConstructorAnnotation.verified.cs | 1 + ...torTests.TestCompoundTypeAlias.verified.cs | 1 + ...eneratorTests.TestGenericClass.verified.cs | 1 + ...ClassWithConstructorParameters.verified.cs | 1 + ...torTests.TestGrainComplexGrain.verified.cs | 38 ++++- ...AnnotatedWithInvokableBaseType.verified.cs | 40 ++++- ...odAnnotatedWithResponseTimeout.verified.cs | 42 ++++- ...TestGrainWithDifferentKeyTypes.verified.cs | 159 ++++++++++++++++-- ...estGrainWithMultipleInterfaces.verified.cs | 81 ++++++++- ...urceGeneratorTests.TestRecords.verified.cs | 1 + ...tDefaultMemberValuesAnnotation.verified.cs | 1 + ...erializerTransparentAnnotation.verified.cs | 1 + ...ressReferenceTrackingAttribute.verified.cs | 1 + ...TestWithUseActivatorAnnotation.verified.cs | 1 + .../InvokablePoolTests.cs | 73 ++++++++ 34 files changed, 527 insertions(+), 55 deletions(-) create mode 100644 test/Orleans.Serialization.UnitTests/InvokablePoolTests.cs diff --git a/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs b/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs index 65abf6fb86d..2b0f44f331e 100644 --- a/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs +++ b/src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Threading; namespace Orleans.Serialization.Invocation { @@ -11,12 +12,25 @@ namespace Orleans.Serialization.Invocation /// Registered as an open generic singleton and injected into generated activators. /// /// The invokable type. - public sealed class InvokablePool where T : class, IInvokable + public sealed class InvokablePool : IDisposable where T : class, IInvokable { private const int MaxPoolSizePerThread = 128; + private readonly ThreadLocal> _perThreadStack = new(static () => new()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Stack GetStack() => PerThreadStack.Stack ??= new(); + private bool TryGetStack([NotNullWhen(true)] out Stack? stack) + { + try + { + stack = _perThreadStack.Value; + return stack is not null; + } + catch (ObjectDisposedException) + { + stack = null; + return false; + } + } /// /// Tries to get an instance from the pool. @@ -25,8 +39,13 @@ public sealed class InvokablePool where T : class, IInvokable /// True if an item was retrieved from the pool; false if the pool was empty. public bool TryGet([NotNullWhen(true)] out T? item) { - var stack = GetStack(); - return stack.TryPop(out item); + if (TryGetStack(out var stack)) + { + return stack.TryPop(out item); + } + + item = null; + return false; } /// @@ -35,19 +54,14 @@ public bool TryGet([NotNullWhen(true)] out T? item) /// The item to return. public void Return(T item) { - var stack = GetStack(); - if (stack.Count < MaxPoolSizePerThread) + if (TryGetStack(out var stack) && stack.Count < MaxPoolSizePerThread) { stack.Push(item); } } - // Nested class to hold ThreadStatic field per generic type instantiation - private static class PerThreadStack - { - [ThreadStatic] - internal static Stack? Stack; - } + /// + public void Dispose() => _perThreadStack.Dispose(); } /// diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs index c132912ac2b..b70eefec497 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_MyTypeAliasStruct : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs index eceac97e8fd..b7738e50802 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs index 28acb2b17d7..398cb602917 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoDataWithFields : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs index 9d5cf66f7bd..4c81d692ea5 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_PublicDemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs index 274e54f3234..a98c7500da1 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_BaseData : global::Orleans.Serialization.Serializers.AbstractTypeSerializer diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs index 1512382dca1..f19303daf81 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec @@ -112,6 +113,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs index ec0671a3b63..fb1802a2537 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IBasicGrain), "6B0E24A1")] @@ -17,6 +18,12 @@ public sealed class Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orle public string arg0; global::TestProject.IBasicGrain _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IBasicGrain), "SayHello", null, new[] { typeof(string) }); + private readonly InvokablePool _pool; + public Invokable_IBasicGrain_GrainReference_6B0E24A1(InvokablePool pool) : base() + { + _pool = pool; + } + public override int GetArgumentCount() => 1; public override string GetMethodName() => "SayHello"; public override string GetInterfaceName() => "TestProject.IBasicGrain"; @@ -29,6 +36,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -63,11 +71,12 @@ internal sealed class Proxy_IBasicGrain : global::Orleans.Runtime.GrainReference { public Proxy_IBasicGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IBasicGrain.SayHello(string arg0) { - var request = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -77,6 +86,12 @@ public Proxy_IBasicGrain(global::Orleans.Runtime.GrainReferenceShared arg0, glob public sealed class Codec_Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IBasicGrain_GrainReference_6B0E24A1(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -128,7 +143,7 @@ public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -138,15 +153,33 @@ public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 DeepCopy(OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IBasicGrain_GrainReference_6B0E24A1(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IBasicGrain_GrainReference_6B0E24A1(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -256,6 +289,7 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IBasicGrain)); config.Interfaces.Add(typeof(global::TestProject.IBasicGrain)); config.InterfaceImplementations.Add(typeof(global::TestProject.BasicGrain)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IBasicGrain_GrainReference_6B0E24A1)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_BasicGrain)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs index d1b76e9656c..1be2758b74b 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs index b43bbf18bb2..f16f2532088 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs index 6b2ce7e9de9..8452727efa8 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs index 6b2ce7e9de9..8452727efa8 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs index e60e2cad1e3..bf817946721 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs index c9ddd38be77..207fe0c4e23 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::IMyGrain), "6D39E404")] @@ -17,6 +18,12 @@ public sealed class Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans public string arg0; global::IMyGrain _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::IMyGrain), "SayHello", null, new[] { typeof(string) }); + private readonly InvokablePool _pool; + public Invokable_IMyGrain_GrainReference_6D39E404(InvokablePool pool) : base() + { + _pool = pool; + } + public override int GetArgumentCount() => 1; public override string GetMethodName() => "SayHello"; public override string GetInterfaceName() => "IMyGrain"; @@ -29,6 +36,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -63,11 +71,12 @@ internal sealed class Proxy_IMyGrain : global::Orleans.Runtime.GrainReference, g { public Proxy_IMyGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::IMyGrain.SayHello(string arg0) { - var request = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -77,6 +86,12 @@ public Proxy_IMyGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global: public sealed class Codec_Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IMyGrain_GrainReference_6D39E404(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -128,7 +143,7 @@ public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 ReadValue(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -138,15 +153,33 @@ public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 ReadValue { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 DeepCopy(OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IMyGrain_GrainReference_6D39E404(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IMyGrain_GrainReference_6D39E404(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404(_arg0); } } @@ -154,6 +187,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase @@ -164,6 +198,7 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.Copiers.Add(typeof(OrleansCodeGen.Copier_Invokable_IMyGrain_GrainReference_6D39E404)); config.InterfaceProxies.Add(typeof(OrleansCodeGen.Proxy_IMyGrain)); config.Interfaces.Add(typeof(global::IMyGrain)); + config.Activators.Add(typeof(OrleansCodeGen.Activator_Invokable_IMyGrain_GrainReference_6D39E404)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); var n3 = n2.Add(typeof(global::IMyGrain)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs index b9f2b281725..73a15a25879 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_MyCustomEnum : global::Orleans.Serialization.Codecs.IFieldCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs index 8faf866a907..3d853ef9937 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_InterfaceCtorParam : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs index 3225ea9b796..85f08affaac 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_NoPublicCtor : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs index 6c7d3441e49..601011e9fad 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_OptionalCtorParams : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs index 55a141b99f0..35b01e0c337 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_MyServiceConsumer : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs index ba0107c2f7d..02516156d25 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_ClassWithGeneratedActivatorConstructor : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs index f095595f889..6e313ab5fe1 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_MyCompoundTypeAliasBaseClass : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs index 4c1db11d05d..bd4d5fc3921 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_GenericData : global::Orleans.Serialization.Codecs.IFieldCodec>, global::Orleans.Serialization.Serializers.IBaseCodec> diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs index 476d688f0ac..3cdf75b77f7 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_GenericWithCtor : global::Orleans.Serialization.Codecs.IFieldCodec>, global::Orleans.Serialization.Serializers.IBaseCodec> diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs index de16baacb7f..dd945bce5ee 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IComplexGrain), "67FE5808")] @@ -21,6 +22,12 @@ public sealed class Invokable_IComplexGrain_GrainReference_67FE5808 : global::Or global::TestProject.IComplexGrain _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IComplexGrain), "ProcessData", null, new[] { typeof(int), typeof(string), typeof(global::TestProject.ComplexData), typeof(global::System.Threading.CancellationToken) }); global::System.Threading.CancellationTokenSource _cts; + private readonly InvokablePool _pool; + public Invokable_IComplexGrain_GrainReference_67FE5808(InvokablePool pool) : base() + { + _pool = pool; + } + public override int GetArgumentCount() => 4; public override string GetMethodName() => "ProcessData"; public override string GetInterfaceName() => "TestProject.IComplexGrain"; @@ -44,6 +51,7 @@ public override void Dispose() _target = default; _cts?.Dispose(); _cts = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -108,11 +116,12 @@ internal sealed class Proxy_IComplexGrain : global::Orleans.Runtime.GrainReferen public Proxy_IComplexGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { _copier0 = OrleansGeneratedCodeHelper.GetService(this, CodecProvider); + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IComplexGrain.ProcessData(int arg0, string arg1, global::TestProject.ComplexData arg2, global::System.Threading.CancellationToken arg3) { - var request = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808(); + var request = GetActivator(0).Create(); request.arg0 = arg0; request.arg1 = arg1; using var copyContext = base.CopyContextPool.GetContext(); @@ -234,10 +243,12 @@ internal sealed class Activator_ComplexData : global::Orleans.Serialization.Acti public sealed class Codec_Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; private readonly global::System.Type _type0 = typeof(global::TestProject.ComplexData); private readonly OrleansCodeGen.TestProject.Codec_ComplexData _codec0; - public Codec_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) + public Codec_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Activators.IActivator _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); _codec0 = OrleansGeneratedCodeHelper.GetService(this, codecProvider); } @@ -312,7 +323,7 @@ public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE580 if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -322,13 +333,14 @@ public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE580 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; private readonly OrleansCodeGen.TestProject.Copier_ComplexData _copier0; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 DeepCopy(OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808(); + var result = _activator.Create(); result.arg0 = original.arg0; result.arg1 = original.arg1; result.arg2 = _copier0.DeepCopy(original.arg2, context); @@ -336,12 +348,25 @@ public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE580 return result; } - public Copier_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) + public Copier_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Activators.IActivator _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); _copier0 = OrleansGeneratedCodeHelper.GetService(this, codecProvider); } } + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IComplexGrain_GrainReference_67FE5808(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808(_arg0); + } + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_ComplexGrain : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec { @@ -452,6 +477,7 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.Interfaces.Add(typeof(global::TestProject.IComplexGrain)); config.InterfaceImplementations.Add(typeof(global::TestProject.ComplexGrain)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ComplexData)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IComplexGrain_GrainReference_67FE5808)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ComplexGrain)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs index 63f779986bd..bd833217770 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IHelloGrain), "5336307F")] @@ -17,8 +18,10 @@ public sealed class Invokable_IHelloGrain_GrainReference_5336307F : global::Orle public string arg0; global::TestProject.IHelloGrain _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IHelloGrain), "SayHello", null, new[] { typeof(string) }); - public Invokable_IHelloGrain_GrainReference_5336307F() : base() + private readonly InvokablePool _pool; + public Invokable_IHelloGrain_GrainReference_5336307F(InvokablePool pool) : base() { + _pool = pool; SetLoggingOptions("Hello"); } @@ -34,6 +37,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -68,11 +72,12 @@ internal sealed class Proxy_IHelloGrain : global::Orleans.Runtime.GrainReference { public Proxy_IHelloGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IHelloGrain.SayHello(string arg0) { - var request = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -82,6 +87,12 @@ public Proxy_IHelloGrain(global::Orleans.Runtime.GrainReferenceShared arg0, glob public sealed class Codec_Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IHelloGrain_GrainReference_5336307F(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -133,7 +144,7 @@ public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -143,15 +154,33 @@ public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F DeepCopy(OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IHelloGrain_GrainReference_5336307F(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IHelloGrain_GrainReference_5336307F(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -261,6 +290,7 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IHelloGrain)); config.Interfaces.Add(typeof(global::TestProject.IHelloGrain)); config.InterfaceImplementations.Add(typeof(global::TestProject.HelloGrain)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IHelloGrain_GrainReference_5336307F)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_HelloGrain)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs index 5b2ba4578cd..001653d9384 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IResponseTimeoutGrain), "6BE752C8")] @@ -17,6 +18,12 @@ public sealed class Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : gl public string arg0; global::TestProject.IResponseTimeoutGrain _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IResponseTimeoutGrain), "LongRunningMethod", null, new[] { typeof(string) }); + private readonly InvokablePool _pool; + public Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(InvokablePool pool) : base() + { + _pool = pool; + } + private static readonly global::System.TimeSpan _responseTimeoutValue = global::System.TimeSpan.FromTicks(100000000L); public override global::System.TimeSpan? GetDefaultResponseTimeout() => _responseTimeoutValue; public override int GetArgumentCount() => 1; @@ -31,6 +38,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -65,11 +73,12 @@ internal sealed class Proxy_IResponseTimeoutGrain : global::Orleans.Runtime.Grai { public Proxy_IResponseTimeoutGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IResponseTimeoutGrain.LongRunningMethod(string arg0) { - var request = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -79,6 +88,12 @@ public Proxy_IResponseTimeoutGrain(global::Orleans.Runtime.GrainReferenceShared public sealed class Codec_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -130,7 +145,7 @@ public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -140,15 +155,33 @@ public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 DeepCopy(OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -161,6 +194,7 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IResponseTimeoutGrain)); config.Interfaces.Add(typeof(global::TestProject.IResponseTimeoutGrain)); config.InterfaceImplementations.Add(typeof(global::TestProject.ResponseTimeoutGrain)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); var n3 = n2.Add(typeof(global::TestProject.IResponseTimeoutGrain)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs index cdc504d80e1..c3b4b5b382a 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IMyGrainWithGuidKey), "8F0FEC0E")] @@ -16,6 +17,12 @@ public sealed class Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : glob { global::TestProject.IMyGrainWithGuidKey _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithGuidKey), "GetGuidValue", null, null); + private readonly InvokablePool _pool; + public Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(InvokablePool pool) : base() + { + _pool = pool; + } + public override string GetMethodName() => "GetGuidValue"; public override string GetInterfaceName() => "TestProject.IMyGrainWithGuidKey"; public override string GetActivityName() => "IMyGrainWithGuidKey/GetGuidValue"; @@ -26,6 +33,7 @@ public sealed class Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : glob public override void Dispose() { _target = default; + _pool.Return(this); } protected override global::System.Threading.Tasks.Task InvokeInner() => _target.GetGuidValue(); @@ -36,11 +44,12 @@ internal sealed class Proxy_IMyGrainWithGuidKey : global::Orleans.Runtime.GrainR { public Proxy_IMyGrainWithGuidKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IMyGrainWithGuidKey.GetGuidValue() { - var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(); + var request = GetActivator(0).Create(); return base.InvokeAsync(request).AsTask(); } } @@ -51,6 +60,12 @@ public sealed class Invokable_IMyGrainWithStringKey_GrainReference_43570316 : gl { global::TestProject.IMyGrainWithStringKey _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithStringKey), "GetStringKey", null, null); + private readonly InvokablePool _pool; + public Invokable_IMyGrainWithStringKey_GrainReference_43570316(InvokablePool pool) : base() + { + _pool = pool; + } + public override string GetMethodName() => "GetStringKey"; public override string GetInterfaceName() => "TestProject.IMyGrainWithStringKey"; public override string GetActivityName() => "IMyGrainWithStringKey/GetStringKey"; @@ -61,6 +76,7 @@ public sealed class Invokable_IMyGrainWithStringKey_GrainReference_43570316 : gl public override void Dispose() { _target = default; + _pool.Return(this); } protected override global::System.Threading.Tasks.Task InvokeInner() => _target.GetStringKey(); @@ -71,11 +87,12 @@ internal sealed class Proxy_IMyGrainWithStringKey : global::Orleans.Runtime.Grai { public Proxy_IMyGrainWithStringKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IMyGrainWithStringKey.GetStringKey() { - var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316(); + var request = GetActivator(0).Create(); return base.InvokeAsync(request).AsTask(); } } @@ -86,6 +103,12 @@ public sealed class Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7A { global::TestProject.IMyGrainWithGuidCompoundKey _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithGuidCompoundKey), "GetGuidAndStringKey", null, null); + private readonly InvokablePool _pool; + public Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(InvokablePool pool) : base() + { + _pool = pool; + } + public override string GetMethodName() => "GetGuidAndStringKey"; public override string GetInterfaceName() => "TestProject.IMyGrainWithGuidCompoundKey"; public override string GetActivityName() => "IMyGrainWithGuidCompoundKey/GetGuidAndStringKey"; @@ -96,6 +119,7 @@ public sealed class Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7A public override void Dispose() { _target = default; + _pool.Return(this); } protected override global::System.Threading.Tasks.Task> InvokeInner() => _target.GetGuidAndStringKey(); @@ -106,11 +130,12 @@ internal sealed class Proxy_IMyGrainWithGuidCompoundKey : global::Orleans.Runtim { public Proxy_IMyGrainWithGuidCompoundKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task> global::TestProject.IMyGrainWithGuidCompoundKey.GetGuidAndStringKey() { - var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(); + var request = GetActivator(0).Create(); return base.InvokeAsync>(request).AsTask(); } } @@ -121,6 +146,12 @@ public sealed class Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814 { global::TestProject.IMyGrainWithIntegerCompoundKey _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithIntegerCompoundKey), "GetIntegerAndStringKey", null, null); + private readonly InvokablePool _pool; + public Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(InvokablePool pool) : base() + { + _pool = pool; + } + public override string GetMethodName() => "GetIntegerAndStringKey"; public override string GetInterfaceName() => "TestProject.IMyGrainWithIntegerCompoundKey"; public override string GetActivityName() => "IMyGrainWithIntegerCompoundKey/GetIntegerAndStringKey"; @@ -131,6 +162,7 @@ public sealed class Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814 public override void Dispose() { _target = default; + _pool.Return(this); } protected override global::System.Threading.Tasks.Task> InvokeInner() => _target.GetIntegerAndStringKey(); @@ -141,11 +173,12 @@ internal sealed class Proxy_IMyGrainWithIntegerCompoundKey : global::Orleans.Run { public Proxy_IMyGrainWithIntegerCompoundKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task> global::TestProject.IMyGrainWithIntegerCompoundKey.GetIntegerAndStringKey() { - var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(); + var request = GetActivator(0).Create(); return base.InvokeAsync>(request).AsTask(); } } @@ -154,6 +187,12 @@ public Proxy_IMyGrainWithIntegerCompoundKey(global::Orleans.Runtime.GrainReferen public sealed class Codec_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -188,7 +227,7 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8 if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -198,14 +237,32 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(); + var result = _activator.Create(); return result; } + + public Copier_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -307,6 +364,12 @@ internal sealed class Activator_GrainWithGuidKey : global::Orleans.Serialization public sealed class Codec_Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IMyGrainWithStringKey_GrainReference_43570316(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -341,7 +404,7 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -351,14 +414,32 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316(); + var result = _activator.Create(); return result; } + + public Copier_Invokable_IMyGrainWithStringKey_GrainReference_43570316(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IMyGrainWithStringKey_GrainReference_43570316(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -460,6 +541,12 @@ internal sealed class Activator_GrainWithStringKey : global::Orleans.Serializati public sealed class Codec_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -494,7 +581,7 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainRef if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -504,14 +591,32 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainRef [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(); + var result = _activator.Create(); return result; } + + public Copier_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -613,6 +718,12 @@ internal sealed class Activator_GrainWithGuidCompoundKey : global::Orleans.Seria public sealed class Codec_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -647,7 +758,7 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_Grain if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -657,14 +768,32 @@ public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_Grain [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(); + var result = _activator.Create(); return result; } + + public Copier_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -795,9 +924,13 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithStringKey)); config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithGuidCompoundKey)); config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithIntegerCompoundKey)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithGuidKey)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IMyGrainWithStringKey_GrainReference_43570316)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithStringKey)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithGuidCompoundKey)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A)); config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithIntegerCompoundKey)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs index 04f152e731d..22c1bc71384 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591, RS0016, RS0041 +#pragma warning disable CS1591, RS0016, RS0041 [assembly: global::Orleans.ApplicationPartAttribute("TestProject")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")] [assembly: global::Orleans.ApplicationPartAttribute("Orleans.Serialization")] @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] [global::Orleans.CompoundTypeAliasAttribute("inv", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IGrainA), "11405B98")] @@ -17,6 +18,12 @@ public sealed class Invokable_IGrainA_GrainReference_11405B98 : global::Orleans. public string arg0; global::TestProject.IGrainA _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IGrainA), "MethodA", null, new[] { typeof(string) }); + private readonly InvokablePool _pool; + public Invokable_IGrainA_GrainReference_11405B98(InvokablePool pool) : base() + { + _pool = pool; + } + public override int GetArgumentCount() => 1; public override string GetMethodName() => "MethodA"; public override string GetInterfaceName() => "TestProject.IGrainA"; @@ -29,6 +36,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -63,11 +71,12 @@ internal sealed class Proxy_IGrainA : global::Orleans.Runtime.GrainReference, gl { public Proxy_IGrainA(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IGrainA.MethodA(string arg0) { - var request = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -80,6 +89,12 @@ public sealed class Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans. public string arg0; global::TestProject.IGrainB _target; private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IGrainB), "MethodB", null, new[] { typeof(string) }); + private readonly InvokablePool _pool; + public Invokable_IGrainB_GrainReference_6B5D7809(InvokablePool pool) : base() + { + _pool = pool; + } + public override int GetArgumentCount() => 1; public override string GetMethodName() => "MethodB"; public override string GetInterfaceName() => "TestProject.IGrainB"; @@ -92,6 +107,7 @@ public override void Dispose() { arg0 = default; _target = default; + _pool.Return(this); } public override object GetArgument(int index) @@ -126,11 +142,12 @@ internal sealed class Proxy_IGrainB : global::Orleans.Runtime.GrainReference, gl { public Proxy_IGrainB(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1) { + EnsureActivator(0); } global::System.Threading.Tasks.Task global::TestProject.IGrainB.MethodB(string arg0) { - var request = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809(); + var request = GetActivator(0).Create(); request.arg0 = arg0; return base.InvokeAsync(request).AsTask(); } @@ -140,6 +157,12 @@ public Proxy_IGrainB(global::Orleans.Runtime.GrainReferenceShared arg0, global:: public sealed class Codec_Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IGrainA_GrainReference_11405B98(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -191,7 +214,7 @@ public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 Read if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -201,21 +224,45 @@ public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 Read [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 DeepCopy(OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IGrainA_GrainReference_11405B98(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IGrainA_GrainReference_11405B98(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Serialization.Codecs.IFieldCodec { private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809); + private readonly global::Orleans.Serialization.Activators.IActivator _activator; + public Codec_Invokable_IGrainB_GrainReference_6B5D7809(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public void Serialize(ref global::Orleans.Serialization.Buffers.Writer writer, OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 instance) where TBufferWriter : global::System.Buffers.IBufferWriter @@ -267,7 +314,7 @@ public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 Read if (field.IsReference) return ReferenceCodec.ReadReference(ref reader, field); field.EnsureWireTypeTagDelimited(); - var result = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809(); + var result = _activator.Create(); ReferenceCodec.MarkValueField(reader.Session); Deserialize(ref reader, result); return result; @@ -277,15 +324,33 @@ public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 Read [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Copier_Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Serialization.Cloning.IDeepCopier { + private readonly global::Orleans.Serialization.Activators.IActivator _activator; [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 DeepCopy(OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 original, global::Orleans.Serialization.Cloning.CopyContext context) { if (original is null) return null; - var result = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809(); + var result = _activator.Create(); result.arg0 = original.arg0; return result; } + + public Copier_Invokable_IGrainB_GrainReference_6B5D7809(global::Orleans.Serialization.Activators.IActivator _activator) + { + this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator); + } + } + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] + internal sealed class Activator_Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Serialization.Activators.IActivator + { + private readonly InvokablePool _arg0; + public Activator_Invokable_IGrainB_GrainReference_6B5D7809(InvokablePool arg0) + { + _arg0 = arg0; + } + + public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 Create() => _arg0.TryGet(out var item) ? item : new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809(_arg0); } [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] @@ -302,6 +367,8 @@ protected override void ConfigureInner(global::Orleans.Serialization.Configurati config.Interfaces.Add(typeof(global::TestProject.IGrainA)); config.Interfaces.Add(typeof(global::TestProject.IGrainB)); config.InterfaceImplementations.Add(typeof(global::TestProject.RealGrain)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IGrainA_GrainReference_11405B98)); + config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_Invokable_IGrainB_GrainReference_6B5D7809)); var n1 = config.CompoundTypeAliases.Add("inv"); var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference)); var n3 = n2.Add(typeof(global::TestProject.IGrainA)); diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs index 600d94ac1b8..0f64d7299fc 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoDataRecordStruct : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs index 3676646d6b9..01c8336aad5 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoClass : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs index 9945825b424..bb21014d26e 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs index 2ac059d8ee6..a57ca817135 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] public sealed class Codec_DemoClass : global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec diff --git a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs index 87efb83e729..c13bf6f74ee 100644 --- a/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs +++ b/test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs @@ -9,6 +9,7 @@ namespace OrleansCodeGen.TestProject { using global::Orleans.Serialization.Codecs; using global::Orleans.Serialization.GeneratedCodeHelpers; + using global::Orleans.Serialization.Invocation; [global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "10.0.0.0"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute] internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase diff --git a/test/Orleans.Serialization.UnitTests/InvokablePoolTests.cs b/test/Orleans.Serialization.UnitTests/InvokablePoolTests.cs new file mode 100644 index 00000000000..61fce93c331 --- /dev/null +++ b/test/Orleans.Serialization.UnitTests/InvokablePoolTests.cs @@ -0,0 +1,73 @@ +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Orleans.Serialization.Invocation; +using Xunit; + +namespace Orleans.Serialization.UnitTests +{ + [Trait("Category", "BVT")] + public class InvokablePoolTests + { + [Fact] + public void InvokablePoolsDoNotShareItemsAcrossInstances() + { + using var firstPool = new InvokablePool(); + using var secondPool = new InvokablePool(); + var item = new TestInvokable(); + + firstPool.Return(item); + + Assert.False(secondPool.TryGet(out _)); + Assert.True(firstPool.TryGet(out var pooledItem)); + Assert.Same(item, pooledItem); + } + + [Fact] + public void ReturnAfterDisposeDoesNotThrow() + { + var pool = new InvokablePool(); + pool.Dispose(); + + pool.Return(new TestInvokable()); + + Assert.False(pool.TryGet(out _)); + } + + private sealed class TestInvokable : IInvokable + { + public object GetTarget() => null; + + public void SetTarget(ITargetHolder holder) { } + + public ValueTask Invoke() => new(Response.Completed); + + public int GetArgumentCount() => 0; + + public object GetArgument(int index) => throw new ArgumentOutOfRangeException(nameof(index)); + + public void SetArgument(int index, object value) => throw new ArgumentOutOfRangeException(nameof(index)); + + public string GetMethodName() => nameof(TestInvokable); + + public string GetInterfaceName() => nameof(TestInvokable); + + public string GetActivityName() => nameof(TestInvokable); + + public MethodInfo GetMethod() => null; + + public Type GetInterfaceType() => typeof(TestInvokable); + + public TimeSpan? GetDefaultResponseTimeout() => null; + + public CancellationToken GetCancellationToken() => CancellationToken.None; + + public bool TryCancel() => false; + + public bool IsCancellable => false; + + public void Dispose() { } + } + } +} From bfb954c54484912477000dc24e4e5e86f6c934ea Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 18:57:33 -0700 Subject: [PATCH 3/7] Dispose pooled invokables with message ownership Dispose invokable request bodies through Message.DisposeBody so local requests are returned to pools exactly once, including expired and failed paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Runtime/InvokableObjectManager.cs | 27 +++++++++++++------ .../Core/InsideRuntimeClient.cs | 14 +++++++++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/Orleans.Core/Runtime/InvokableObjectManager.cs b/src/Orleans.Core/Runtime/InvokableObjectManager.cs index 3bed78f414b..f0a82b51b2b 100644 --- a/src/Orleans.Core/Runtime/InvokableObjectManager.cs +++ b/src/Orleans.Core/Runtime/InvokableObjectManager.cs @@ -253,6 +253,12 @@ bool TryDequeueMessage([NotNullWhen(true)] out Message? message) private async Task ProcessMessageAsync(Message message) { + var disposeBody = message.BodyObject is IInvokable; + if (disposeBody) + { + message.DisposeBodyObject = true; + } + try { if (message.IsExpired) @@ -312,20 +318,25 @@ private async Task ProcessMessageAsync(Message message) { this.ReportException(message, exc); } - finally - { - // Clear the running request when done. - lock (Messages) - { - _runningRequests.Remove(message); - } - } } catch (Exception outerException) { // Ignore and keep looping. LogErrorProcessingMessage(_manager.logger, outerException, message); } + finally + { + if (disposeBody) + { + message.DisposeBody(); + } + + // Clear the running request when done. + lock (Messages) + { + _runningRequests.Remove(message); + } + } } private void SendResponseAsync(Message message, Response resultObject) diff --git a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs index 29e4abaac67..41854185bf8 100644 --- a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs +++ b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs @@ -258,6 +258,12 @@ public void SniffIncomingMessage(Message message) public async Task Invoke(IGrainContext target, Message message) { + var disposeBody = message.BodyObject is IInvokable; + if (disposeBody) + { + message.DisposeBodyObject = true; + } + try { // Don't process messages that have already timed out @@ -294,7 +300,6 @@ public async Task Invoke(IGrainContext target, Message message) response = this.responseCopier.Copy(response); } - invokable.Dispose(); break; } default: @@ -346,6 +351,13 @@ public async Task Invoke(IGrainContext target, Message message) SafeSendExceptionResponse(message, exc2); } } + finally + { + if (disposeBody) + { + message.DisposeBody(); + } + } } private void SafeSendResponse(Message message, Response response) From bda7c26155b84c10fa6f00af38880a51c4ed8774 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 19:12:18 -0700 Subject: [PATCH 4/7] Transfer invokable message body ownership Prevent response callbacks from returning locally executing invokables to the pool while they are still in use. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Orleans.Core/Runtime/InvokableObjectManager.cs | 14 +++++++++----- src/Orleans.Runtime/Core/InsideRuntimeClient.cs | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Orleans.Core/Runtime/InvokableObjectManager.cs b/src/Orleans.Core/Runtime/InvokableObjectManager.cs index f0a82b51b2b..5f533821aac 100644 --- a/src/Orleans.Core/Runtime/InvokableObjectManager.cs +++ b/src/Orleans.Core/Runtime/InvokableObjectManager.cs @@ -253,10 +253,10 @@ bool TryDequeueMessage([NotNullWhen(true)] out Message? message) private async Task ProcessMessageAsync(Message message) { - var disposeBody = message.BodyObject is IInvokable; - if (disposeBody) + var invokable = message.BodyObject as IInvokable; + if (invokable is not null) { - message.DisposeBodyObject = true; + message.DisposeBodyObject = false; } try @@ -326,9 +326,13 @@ private async Task ProcessMessageAsync(Message message) } finally { - if (disposeBody) + if (invokable is not null) { - message.DisposeBody(); + invokable.Dispose(); + if (ReferenceEquals(message.BodyObject, invokable)) + { + message.BodyObject = null; + } } // Clear the running request when done. diff --git a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs index 41854185bf8..8c96e85688b 100644 --- a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs +++ b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs @@ -258,10 +258,10 @@ public void SniffIncomingMessage(Message message) public async Task Invoke(IGrainContext target, Message message) { - var disposeBody = message.BodyObject is IInvokable; - if (disposeBody) + var request = message.BodyObject as IInvokable; + if (request is not null) { - message.DisposeBodyObject = true; + message.DisposeBodyObject = false; } try @@ -353,9 +353,13 @@ public async Task Invoke(IGrainContext target, Message message) } finally { - if (disposeBody) + if (request is not null) { - message.DisposeBody(); + request.Dispose(); + if (ReferenceEquals(message.BodyObject, request)) + { + message.BodyObject = null; + } } } } From a6b0c03415d42c76971a825346a759ad758f329e Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 19:24:19 -0700 Subject: [PATCH 5/7] Keep object pools instance scoped Use per-pool thread-local storage so serializer sessions and copy contexts are not shared across service providers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Invocation/Pools/ConcurrentObjectPool.cs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs b/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs index d4630892f0f..b138268c74a 100644 --- a/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs +++ b/src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs @@ -1,7 +1,7 @@ #nullable enable using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; +using System.Threading; using Microsoft.Extensions.ObjectPool; namespace Orleans.Serialization.Invocation @@ -16,17 +16,15 @@ public ConcurrentObjectPool() : base(new()) internal class ConcurrentObjectPool : ObjectPool where T : class where TPoolPolicy : IPooledObjectPolicy { private readonly TPoolPolicy _policy; + private readonly ThreadLocal> _objects = new(static () => new()); public ConcurrentObjectPool(TPoolPolicy policy) => _policy = policy; public int MaxPoolSize { get; set; } = int.MaxValue; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Stack GetStack() => PerThreadStack.Stack ??= new(); - public override T Get() { - var stack = GetStack(); + var stack = _objects.Value!; if (stack.TryPop(out var result)) { return result; @@ -39,19 +37,12 @@ public override void Return(T obj) { if (_policy.Return(obj)) { - var stack = GetStack(); + var stack = _objects.Value!; if (stack.Count < MaxPoolSize) { stack.Push(obj); } } } - - // Nested class to hold ThreadStatic field per generic type instantiation - private static class PerThreadStack - { - [ThreadStatic] - internal static Stack? Stack; - } } } From 4c498eeae28caeaee60b09208a8230938ecf2314 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 19:49:25 -0700 Subject: [PATCH 6/7] Fix invokable request ownership Keep pooled invokable request bodies alive until the outgoing invocation completes so retry filters can inspect and mutate arguments after failed attempts. Avoid receiver-side disposal for shared local request bodies, while preserving disposal for deserialized inbound requests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Runtime/GrainReference.cs | 39 ++++++---- src/Orleans.Core/Messaging/Message.cs | 8 ++ src/Orleans.Core/Messaging/MessageFactory.cs | 1 + .../Messaging/MessageSerializer.cs | 6 ++ src/Orleans.Core/Networking/Connection.cs | 2 +- src/Orleans.Core/Runtime/CallbackData.cs | 12 +-- .../Runtime/GrainReferenceRuntime.cs | 76 +++++++++++++++---- .../Runtime/InvokableObjectManager.cs | 7 +- .../Core/InsideRuntimeClient.cs | 5 +- .../Messaging/MessageCenter.cs | 5 ++ 10 files changed, 113 insertions(+), 48 deletions(-) diff --git a/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs b/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs index 9777362c33e..3923f2f93d9 100644 --- a/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs +++ b/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs @@ -91,19 +91,34 @@ public GrainReferenceShared( /// The invokable type. /// The index of the activator in the array. public void EnsureActivator(int index) + => _ = GetOrCreateActivator(index); + + /// + /// Gets an activator from the cached array at the specified index. + /// Callers must ensure has been called first. + /// + /// The invokable type. + /// The index of the activator in the array. + /// The activator for the specified invokable type. + public IActivator GetActivator(int index) { var activators = _activators; - if (activators.Length > index && activators[index] is not null) + if (activators.Length > index && activators[index] is IActivator result) { - return; + return result; } + return GetOrCreateActivator(index); + } + + private IActivator GetOrCreateActivator(int index) + { lock (_activatorsLock) { - activators = _activators; - if (activators.Length > index && activators[index] is not null) + var activators = _activators; + if (activators.Length > index && activators[index] is IActivator result) { - return; + return result; } // Grow array if necessary @@ -115,20 +130,12 @@ public void EnsureActivator(int index) } // Create the activator - activators[index] = CodecProvider.GetActivator(); + result = CodecProvider.GetActivator(); + activators[index] = result; _activators = activators; + return result; } } - - /// - /// Gets an activator from the cached array at the specified index. - /// Callers must ensure has been called first. - /// - /// The invokable type. - /// The index of the activator in the array. - /// The activator for the specified invokable type. - public IActivator GetActivator(int index) - => (IActivator)_activators[index]; } /// diff --git a/src/Orleans.Core/Messaging/Message.cs b/src/Orleans.Core/Messaging/Message.cs index 1d3f2a0dbbf..2e7e5230b24 100644 --- a/src/Orleans.Core/Messaging/Message.cs +++ b/src/Orleans.Core/Messaging/Message.cs @@ -22,6 +22,12 @@ internal sealed class Message : ISpanFormattable [NonSerialized] internal bool DisposeBodyObject; + /// + /// Indicates that is shared with the local sender. + /// + [NonSerialized] + internal bool BodyObjectIsShared; + public CoarseStopwatch _timeToExpiry; public object? BodyObject { get; set; } @@ -387,6 +393,7 @@ internal void DisposeBody() { (BodyObject as IDisposable)?.Dispose(); DisposeBodyObject = false; + BodyObjectIsShared = false; BodyObject = null; } } @@ -400,6 +407,7 @@ internal void Reset() _timeToExpiry = default; DisposeBody(); BodyObject = null; + BodyObjectIsShared = false; _headers = default; _id = default; _requestContextData = null; diff --git a/src/Orleans.Core/Messaging/MessageFactory.cs b/src/Orleans.Core/Messaging/MessageFactory.cs index 29f9a9d2d8c..6c60673548b 100644 --- a/src/Orleans.Core/Messaging/MessageFactory.cs +++ b/src/Orleans.Core/Messaging/MessageFactory.cs @@ -42,6 +42,7 @@ public Message CreateMessage(object body, InvokeMethodOptions options) IsAlwaysInterleave = (options & InvokeMethodOptions.AlwaysInterleave) != 0, BodyObject = body, DisposeBodyObject = body is IInvokable, + BodyObjectIsShared = body is IInvokable, RequestContextData = RequestContextExtensions.Export(_deepCopier), }; diff --git a/src/Orleans.Core/Messaging/MessageSerializer.cs b/src/Orleans.Core/Messaging/MessageSerializer.cs index 76a41537569..7661975d25b 100644 --- a/src/Orleans.Core/Messaging/MessageSerializer.cs +++ b/src/Orleans.Core/Messaging/MessageSerializer.cs @@ -140,6 +140,12 @@ private void ReadBodyObject(Message message, ref Reader reader) var bodyCodec = _codecProvider.GetCodec(field.FieldType); message.BodyObject = bodyCodec.ReadValue(ref reader, field); } + + if (message.Direction is Directions.Request or Directions.OneWay) + { + message.DisposeBodyObject = message.BodyObject is IInvokable; + message.BodyObjectIsShared = false; + } } private ResponseCodec GetRawCodec(Type fieldType) diff --git a/src/Orleans.Core/Networking/Connection.cs b/src/Orleans.Core/Networking/Connection.cs index cc660b0ee80..920bc30debb 100644 --- a/src/Orleans.Core/Networking/Connection.cs +++ b/src/Orleans.Core/Networking/Connection.cs @@ -383,7 +383,7 @@ private async Task ProcessOutgoing() } // Dispose one-way request bodies after they've been sent. - // Request-response bodies are disposed when the callback completes. + // Request-response bodies are disposed when the invocation completes. foreach (var msg in inflight) { if (msg.Direction == Message.Directions.OneWay) diff --git a/src/Orleans.Core/Runtime/CallbackData.cs b/src/Orleans.Core/Runtime/CallbackData.cs index 20bdb32629e..98536d69ce7 100644 --- a/src/Orleans.Core/Runtime/CallbackData.cs +++ b/src/Orleans.Core/Runtime/CallbackData.cs @@ -108,7 +108,6 @@ private void OnCancellation() OrleansCallBackDataEvent.Instance.OnCanceled(Message); context.Complete(Response.FromException(new OperationCanceledException(_cancellationTokenRegistration.Token))); _cancellationTokenRegistration.Dispose(); - this.Message.DisposeBody(); } public void OnTimeout() @@ -139,7 +138,6 @@ public void OnTimeout() var exception = new TimeoutException($"Response did not arrive on time in {timeout} for message: {msg}. {statusMessage}"); context.Complete(Response.FromException(exception)); - this.Message.DisposeBody(); } public void OnTargetSiloFail() @@ -160,7 +158,6 @@ public void OnTargetSiloFail() LogTargetSiloFail(this.shared.Logger, msg, statusMessage, Constants.TroubleshootingHelpLink); var exception = new SiloUnavailableException($"The target silo became unavailable for message: {msg}. {statusMessage}See {Constants.TroubleshootingHelpLink} for troubleshooting help."); this.context.Complete(Response.FromException(exception)); - this.Message.DisposeBody(); } public void DoCallback(Message response) @@ -177,14 +174,7 @@ public void DoCallback(Message response) _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation. - try - { - ResponseCallback(response, this.context); - } - finally - { - this.Message.DisposeBody(); - } + ResponseCallback(response, this.context); } private static void ResponseCallback(Message message, IResponseCompletionSource context) diff --git a/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs b/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs index 8d90f35b228..56329715d69 100644 --- a/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs +++ b/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs @@ -41,10 +41,7 @@ public ValueTask InvokeMethodAsync(GrainReference reference, I // TODO: Remove expensive interface type check if (this.filters.Length == 0 && request is not IOutgoingGrainCallFilter) { - SetGrainCancellationTokensTarget(reference, request); - var responseCompletionSource = ResponseCompletionSourcePool.Get(); - this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); - return responseCompletionSource.AsValueTask(); + return InvokeMethodAsyncCore(reference, request, options); } else { @@ -57,10 +54,7 @@ public ValueTask InvokeMethodAsync(GrainReference reference, IInvokable request, // TODO: Remove expensive interface type check if (filters.Length == 0 && request is not IOutgoingGrainCallFilter) { - SetGrainCancellationTokensTarget(reference, request); - var responseCompletionSource = ResponseCompletionSourcePool.Get(); - this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); - return responseCompletionSource.AsVoidValueTask(); + return InvokeMethodAsyncCore(reference, request, options); } else { @@ -86,17 +80,69 @@ public void InvokeMethod(GrainReference reference, IInvokable request, InvokeMet private async ValueTask InvokeMethodWithFiltersAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options) { - SetGrainCancellationTokensTarget(reference, request); - var invoker = new OutgoingCallInvoker(reference, request, options, this.sendRequest, this.filters); - await invoker.Invoke(); - return invoker.TypedResult; + try + { + SetGrainCancellationTokensTarget(reference, request); + var invoker = new OutgoingCallInvoker(reference, request, options, this.sendRequest, this.filters); + await invoker.Invoke(); + return invoker.TypedResult; + } + finally + { + DisposeRequest(request, options); + } } private async ValueTask InvokeMethodWithFiltersAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options) { - SetGrainCancellationTokensTarget(reference, request); - var invoker = new OutgoingCallInvoker(reference, request, options, this.sendRequest, this.filters); - await invoker.Invoke(); + try + { + SetGrainCancellationTokensTarget(reference, request); + var invoker = new OutgoingCallInvoker(reference, request, options, this.sendRequest, this.filters); + await invoker.Invoke(); + } + finally + { + DisposeRequest(request, options); + } + } + + private async ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) + { + try + { + SetGrainCancellationTokensTarget(reference, request); + var responseCompletionSource = ResponseCompletionSourcePool.Get(); + this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); + return await responseCompletionSource.AsValueTask(); + } + finally + { + DisposeRequest(request, options); + } + } + + private async ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) + { + try + { + SetGrainCancellationTokensTarget(reference, request); + var responseCompletionSource = ResponseCompletionSourcePool.Get(); + this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); + await responseCompletionSource.AsVoidValueTask(); + } + finally + { + DisposeRequest(request, options); + } + } + + private static void DisposeRequest(IInvokable request, InvokeMethodOptions options) + { + if ((options & InvokeMethodOptions.OneWay) == 0) + { + request.Dispose(); + } } public object Cast(IAddressable grain, Type grainInterface) diff --git a/src/Orleans.Core/Runtime/InvokableObjectManager.cs b/src/Orleans.Core/Runtime/InvokableObjectManager.cs index 5f533821aac..3dc88f8c5e6 100644 --- a/src/Orleans.Core/Runtime/InvokableObjectManager.cs +++ b/src/Orleans.Core/Runtime/InvokableObjectManager.cs @@ -254,7 +254,8 @@ bool TryDequeueMessage([NotNullWhen(true)] out Message? message) private async Task ProcessMessageAsync(Message message) { var invokable = message.BodyObject as IInvokable; - if (invokable is not null) + var disposeInvokable = invokable is not null && message.DisposeBodyObject; + if (disposeInvokable) { message.DisposeBodyObject = false; } @@ -326,9 +327,9 @@ private async Task ProcessMessageAsync(Message message) } finally { - if (invokable is not null) + if (disposeInvokable) { - invokable.Dispose(); + invokable!.Dispose(); if (ReferenceEquals(message.BodyObject, invokable)) { message.BodyObject = null; diff --git a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs index 8c96e85688b..4738872cda6 100644 --- a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs +++ b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs @@ -259,7 +259,8 @@ public void SniffIncomingMessage(Message message) public async Task Invoke(IGrainContext target, Message message) { var request = message.BodyObject as IInvokable; - if (request is not null) + var disposeRequest = request is not null && message.DisposeBodyObject; + if (disposeRequest) { message.DisposeBodyObject = false; } @@ -353,7 +354,7 @@ public async Task Invoke(IGrainContext target, Message message) } finally { - if (request is not null) + if (disposeRequest) { request.Dispose(); if (ReferenceEquals(message.BodyObject, request)) diff --git a/src/Orleans.Runtime/Messaging/MessageCenter.cs b/src/Orleans.Runtime/Messaging/MessageCenter.cs index cc3a7a0b65b..220f8415199 100644 --- a/src/Orleans.Runtime/Messaging/MessageCenter.cs +++ b/src/Orleans.Runtime/Messaging/MessageCenter.cs @@ -184,6 +184,11 @@ public void SendMessage(Message msg) MessagingInstruments.LocalMessagesSentCounterAggregator.Add(1); + if (msg.Direction == Message.Directions.Request && msg.BodyObjectIsShared) + { + msg.DisposeBodyObject = false; + } + this.ReceiveMessage(msg); } else From 7c75b3cc86487d6288bc0c70f87bf9cf9f461935 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Wed, 29 Apr 2026 20:28:49 -0700 Subject: [PATCH 7/7] Preserve synchronous cancellation behavior Keep no-filter cancellation checks synchronous while still disposing pooled requests after response completion. Copy shared local request bodies before loopback delivery so target-side execution and cancellation cannot reset the caller's pooled invokable before outgoing filters finish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Orleans.Core/Messaging/MessageFactory.cs | 2 ++ .../Runtime/GrainReferenceRuntime.cs | 36 ++++++++++++++++--- .../Messaging/MessageCenter.cs | 6 ++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/Orleans.Core/Messaging/MessageFactory.cs b/src/Orleans.Core/Messaging/MessageFactory.cs index 6c60673548b..92ae88f84f2 100644 --- a/src/Orleans.Core/Messaging/MessageFactory.cs +++ b/src/Orleans.Core/Messaging/MessageFactory.cs @@ -50,6 +50,8 @@ public Message CreateMessage(object body, InvokeMethodOptions options) return message; } + public object CopyBodyObject(object body) => _deepCopier.Copy(body); + private CorrelationId GetNextCorrelationId() { var id = _seed ^ Interlocked.Increment(ref _nextId); diff --git a/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs b/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs index 56329715d69..5b6aae67b5b 100644 --- a/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs +++ b/src/Orleans.Core/Runtime/GrainReferenceRuntime.cs @@ -107,13 +107,27 @@ private async ValueTask InvokeMethodWithFiltersAsync(GrainReference reference, I } } - private async ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) + private ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) { + ResponseCompletionSource responseCompletionSource; try { SetGrainCancellationTokensTarget(reference, request); - var responseCompletionSource = ResponseCompletionSourcePool.Get(); + responseCompletionSource = ResponseCompletionSourcePool.Get(); this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); + return CompleteInvokeAsync(responseCompletionSource, request, options); + } + catch + { + DisposeRequest(request, options); + throw; + } + } + + private static async ValueTask CompleteInvokeAsync(ResponseCompletionSource responseCompletionSource, IInvokable request, InvokeMethodOptions options) + { + try + { return await responseCompletionSource.AsValueTask(); } finally @@ -122,13 +136,27 @@ private async ValueTask InvokeMethodAsyncCore(GrainReference r } } - private async ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) + private ValueTask InvokeMethodAsyncCore(GrainReference reference, IInvokable request, InvokeMethodOptions options) { + ResponseCompletionSource responseCompletionSource; try { SetGrainCancellationTokensTarget(reference, request); - var responseCompletionSource = ResponseCompletionSourcePool.Get(); + responseCompletionSource = ResponseCompletionSourcePool.Get(); this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options); + return CompleteInvokeAsync(responseCompletionSource, request, options); + } + catch + { + DisposeRequest(request, options); + throw; + } + } + + private static async ValueTask CompleteInvokeAsync(ResponseCompletionSource responseCompletionSource, IInvokable request, InvokeMethodOptions options) + { + try + { await responseCompletionSource.AsVoidValueTask(); } finally diff --git a/src/Orleans.Runtime/Messaging/MessageCenter.cs b/src/Orleans.Runtime/Messaging/MessageCenter.cs index 220f8415199..422f260c7af 100644 --- a/src/Orleans.Runtime/Messaging/MessageCenter.cs +++ b/src/Orleans.Runtime/Messaging/MessageCenter.cs @@ -184,9 +184,11 @@ public void SendMessage(Message msg) MessagingInstruments.LocalMessagesSentCounterAggregator.Add(1); - if (msg.Direction == Message.Directions.Request && msg.BodyObjectIsShared) + if (msg.Direction == Message.Directions.Request && msg.BodyObjectIsShared && msg.BodyObject is { } body) { - msg.DisposeBodyObject = false; + msg.BodyObject = this.messageFactory.CopyBodyObject(body); + msg.DisposeBodyObject = msg.BodyObject is IInvokable; + msg.BodyObjectIsShared = false; } this.ReceiveMessage(msg);