Skip to content

perf(codegen): pool generated IInvokable request objects#10070

Draft
ReubenBond wants to merge 7 commits into
dotnet:mainfrom
ReubenBond:split/invokable-pooling
Draft

perf(codegen): pool generated IInvokable request objects#10070
ReubenBond wants to merge 7 commits into
dotnet:mainfrom
ReubenBond:split/invokable-pooling

Conversation

@ReubenBond

@ReubenBond ReubenBond commented Apr 30, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds instance-scoped, thread-local pooling for generated IInvokable request objects for non-generic grain methods and registers InvokablePool<T> with serializer services.
  • Updates source generation and proxies so pooled invokable activators are cached, requests are rented or created via activators, and disposed requests reset their fields and return to their pool.
  • Adds message body ownership and disposal handling across send, receive, local-message, one-way, and request/response paths so pooled invokables are not shared or returned too early.
  • Includes follow-up fixes for pool isolation, ownership transfer, instance-scoped pools, and preserving synchronous cancellation behavior.

Validation

  • git diff --check
  • conflict-marker scan
  • dotnet build src\Orleans.Serialization\Orleans.Serialization.csproj -m
  • dotnet build src\Orleans.CodeGenerator\Orleans.CodeGenerator.csproj -m
  • targeted TypeEncodingTests passed on net8/net10; netcoreapp3.1 skipped by xUnit loader

Dependencies / notes

  • This PR targets main, but is logically related to message pooling/ref-counting work and may need coordination with that PR.
  • Included only InvokablePool/ConcurrentObjectPool ThreadStatic pieces; excluded SEDA, callback pooling, networking rewrite, and benchmarks.
Microsoft Reviewers: Open in CodeFlow

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces pooling for generated IInvokable request objects (primarily for non-generic grain methods) and extends the Orleans runtime messaging pipeline to correctly manage request-body ownership/disposal so pooled invokables are not reused too early.

Changes:

  • Added InvokablePool<T> (thread-local, instance-scoped pool) and registered it with serializer services for DI injection into generated activators.
  • Updated source generation/proxies/codecs/copiers so invokables are created via cached activators and returned to their pool on Dispose().
  • Updated messaging/runtime send/receive/local/one-way/request-response paths to transfer message-body ownership and dispose pooled invokables at the correct time; updated unit tests and generator snapshot baselines.
Show a summary per file
File Description
test/Orleans.Serialization.UnitTests/InvokablePoolTests.cs Adds unit tests validating pool instance isolation and safe behavior after disposal.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs Updates expected generated grain proxy/invokable output to use activators and return invokables to pools.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs Updates expected generated output to include invocation/pooling-related usings.
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs Updates expected generated output to include invocation/pooling-related usings.
src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs Introduces InvokablePool<T> and keeps the prior static helper for backward compatibility.
src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs Enables nullable annotations and adjusts ThreadLocal usage.
src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs Registers open-generic InvokablePool<> with serializer services.
src/Orleans.Runtime/Messaging/MessageCenter.cs Copies shared request bodies for local delivery to avoid premature reuse of pooled invokables.
src/Orleans.Runtime/Core/InsideRuntimeClient.cs Adds explicit request-body ownership transfer and disposal on the receiver side.
src/Orleans.Core/Runtime/InvokableObjectManager.cs Adds explicit request-body ownership transfer and disposal in the local object manager path.
src/Orleans.Core/Runtime/GrainReferenceRuntime.cs Ensures requests are disposed at the correct time for request/response vs one-way.
src/Orleans.Core/Networking/Connection.cs Disposes one-way request bodies after they have been sent.
src/Orleans.Core/Messaging/MessageSerializer.cs Marks deserialized request/one-way bodies as disposable invokables and not shared.
src/Orleans.Core/Messaging/MessageFactory.cs Initializes message body ownership/disposal flags and adds a helper to copy body objects.
src/Orleans.Core/Messaging/Message.cs Adds body ownership/disposal flags plus helper methods to dispose/reset the message body.
src/Orleans.Core.Abstractions/Runtime/GrainReference.cs Adds cached activator storage on GrainReferenceShared and exposes proxy helpers.
src/Orleans.CodeGenerator/ProxyGenerator.cs Generates proxies which cache activators and allocate requests via activators where applicable.
src/Orleans.CodeGenerator/LibraryTypes.cs Adds InvokablePool<> to known library types for generation.
src/Orleans.CodeGenerator/InvokableGenerator.cs Generates invokables with pool support and emits code to return to pool on Dispose().
src/Orleans.CodeGenerator/CodeGenerator.cs Adds Orleans.Serialization.Invocation to generated file usings.
src/Orleans.CodeGenerator/ActivatorGenerator.cs Generates pool-aware activators which rent from InvokablePool<T> before allocating.

Copilot's findings

  • Files reviewed: 50/50 changed files
  • Comments generated: 9

@@ -1,4 +1,4 @@
#pragma warning disable CS1591, RS0016, RS0041
#pragma warning disable CS1591, RS0016, RS0041
{
private const string CopyContextPoolMemberName = "CopyContextPool";
private const string CodecProviderMemberName = "CodecProvider";
private const string SharedMemberName = "Shared";
@@ -1,8 +1,9 @@
#nullable enable
using System;
@@ -1,4 +1,4 @@
#pragma warning disable CS1591, RS0016, RS0041
#pragma warning disable CS1591, RS0016, RS0041
Comment on lines +1 to 2
#pragma warning disable CS1591, RS0016, RS0041
[assembly: global::Orleans.ApplicationPartAttribute("TestProject")]
Comment on lines +1 to 2
#pragma warning disable CS1591, RS0016, RS0041
[assembly: global::Orleans.ApplicationPartAttribute("TestProject")]
Comment on lines +1 to 2
#pragma warning disable CS1591, RS0016, RS0041
[assembly: global::Orleans.ApplicationPartAttribute("TestProject")]
Comment on lines +1 to 2
#pragma warning disable CS1591, RS0016, RS0041
[assembly: global::Orleans.ApplicationPartAttribute("TestProject")]
Comment on lines +1 to 2
#pragma warning disable CS1591, RS0016, RS0041
[assembly: global::Orleans.ApplicationPartAttribute("TestProject")]
ReubenBond and others added 7 commits April 30, 2026 08:29
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
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>
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>
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>
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>
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>
@ReubenBond ReubenBond force-pushed the split/invokable-pooling branch from d5e0598 to 7c75b3c Compare April 30, 2026 15:33
@ReubenBond ReubenBond changed the title Pool generated IInvokable request objects perf(codegen): pool generated IInvokable request objects May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants