66using Orleans . CodeGeneration ;
77using Orleans . GrainReferences ;
88using Orleans . Metadata ;
9+ using Orleans . Serialization ;
910using Orleans . Serialization . Invocation ;
1011
1112namespace Orleans . Runtime
@@ -17,20 +18,23 @@ internal class GrainReferenceRuntime : IGrainReferenceRuntime
1718 private readonly IGrainCancellationTokenRuntime cancellationTokenRuntime ;
1819 private readonly IOutgoingGrainCallFilter [ ] filters ;
1920 private readonly Action < GrainReference , IResponseCompletionSource , IInvokable , InvokeMethodOptions > sendRequest ;
21+ private readonly DeepCopier requestCopier ;
2022
2123 public GrainReferenceRuntime (
2224 IRuntimeClient runtimeClient ,
2325 IGrainCancellationTokenRuntime cancellationTokenRuntime ,
2426 IEnumerable < IOutgoingGrainCallFilter > outgoingCallFilters ,
2527 GrainReferenceActivator referenceActivator ,
26- GrainInterfaceTypeResolver interfaceTypeResolver )
28+ GrainInterfaceTypeResolver interfaceTypeResolver ,
29+ DeepCopier requestCopier )
2730 {
2831 this . RuntimeClient = runtimeClient ;
2932 this . cancellationTokenRuntime = cancellationTokenRuntime ;
3033 this . referenceActivator = referenceActivator ;
3134 this . interfaceTypeResolver = interfaceTypeResolver ;
3235 this . filters = outgoingCallFilters . ToArray ( ) ;
33- this . sendRequest = ( GrainReference reference , IResponseCompletionSource callback , IInvokable body , InvokeMethodOptions options ) => RuntimeClient . SendRequest ( reference , body , callback , options ) ;
36+ this . requestCopier = requestCopier ;
37+ this . sendRequest = SendFilteredRequest ;
3438 }
3539
3640 public IRuntimeClient RuntimeClient { get ; private set ; }
@@ -64,25 +68,26 @@ public ValueTask InvokeMethodAsync(GrainReference reference, IInvokable request,
6468 public void InvokeMethod ( GrainReference reference , IInvokable request , InvokeMethodOptions options )
6569 {
6670 Debug . Assert ( ( options & InvokeMethodOptions . OneWay ) != 0 ) ;
67- var disposeRequest = true ;
71+ var requestTransferred = false ;
6872
6973 try
7074 {
7175 // TODO: Remove expensive interface type check
7276 if ( filters . Length == 0 && request is not IOutgoingGrainCallFilter )
7377 {
7478 SetGrainCancellationTokensTarget ( reference , request ) ;
79+ requestTransferred = true ;
7580 this . RuntimeClient . SendRequest ( reference , request , context : null , options ) ;
7681 }
7782 else
7883 {
7984 InvokeMethodWithFiltersAsync ( reference , request , options ) . AsTask ( ) . Ignore ( ) ;
80- disposeRequest = false ;
85+ requestTransferred = true ;
8186 }
8287 }
8388 finally
8489 {
85- if ( disposeRequest )
90+ if ( ! requestTransferred )
8691 {
8792 DisposeRequest ( request ) ;
8893 }
@@ -121,60 +126,48 @@ private async ValueTask InvokeMethodWithFiltersAsync(GrainReference reference, I
121126 private ValueTask < TResult ? > InvokeMethodAsyncCore < TResult > ( GrainReference reference , IInvokable request , InvokeMethodOptions options )
122127 {
123128 ResponseCompletionSource < TResult > ? responseCompletionSource = null ;
129+ var requestTransferred = false ;
124130 try
125131 {
126132 SetGrainCancellationTokensTarget ( reference , request ) ;
127133 responseCompletionSource = ResponseCompletionSourcePool . Get < TResult > ( ) ;
134+ requestTransferred = true ;
128135 this . RuntimeClient . SendRequest ( reference , request , responseCompletionSource , options ) ;
129- return CompleteInvokeAsync ( responseCompletionSource , request , options ) ;
136+ return responseCompletionSource . AsValueTask ( ) ;
130137 }
131138 catch
132139 {
133140 responseCompletionSource ? . Reset ( ) ;
134- DisposeRequest ( request ) ;
135- throw ;
136- }
137- }
141+ if ( ! requestTransferred )
142+ {
143+ DisposeRequest ( request ) ;
144+ }
138145
139- private static async ValueTask < TResult ? > CompleteInvokeAsync < TResult > ( ResponseCompletionSource < TResult > responseCompletionSource , IInvokable request , InvokeMethodOptions options )
140- {
141- try
142- {
143- return await responseCompletionSource . AsValueTask ( ) ;
144- }
145- finally
146- {
147- DisposeRequest ( request ) ;
146+ throw ;
148147 }
149148 }
150149
151150 private ValueTask InvokeMethodAsyncCore ( GrainReference reference , IInvokable request , InvokeMethodOptions options )
152151 {
153152 ResponseCompletionSource ? responseCompletionSource = null ;
153+ var requestTransferred = false ;
154154 try
155155 {
156156 SetGrainCancellationTokensTarget ( reference , request ) ;
157157 responseCompletionSource = ResponseCompletionSourcePool . Get ( ) ;
158+ requestTransferred = true ;
158159 this . RuntimeClient . SendRequest ( reference , request , responseCompletionSource , options ) ;
159- return CompleteInvokeAsync ( responseCompletionSource , request , options ) ;
160+ return responseCompletionSource . AsVoidValueTask ( ) ;
160161 }
161162 catch
162163 {
163164 responseCompletionSource ? . Reset ( ) ;
164- DisposeRequest ( request ) ;
165- throw ;
166- }
167- }
165+ if ( ! requestTransferred )
166+ {
167+ DisposeRequest ( request ) ;
168+ }
168169
169- private static async ValueTask CompleteInvokeAsync ( ResponseCompletionSource responseCompletionSource , IInvokable request , InvokeMethodOptions options )
170- {
171- try
172- {
173- await responseCompletionSource . AsVoidValueTask ( ) ;
174- }
175- finally
176- {
177- DisposeRequest ( request ) ;
170+ throw ;
178171 }
179172 }
180173
@@ -186,6 +179,18 @@ private static void DisposeRequest(IInvokable request)
186179 }
187180 }
188181
182+ private void SendFilteredRequest (
183+ GrainReference reference ,
184+ IResponseCompletionSource callback ,
185+ IInvokable request ,
186+ InvokeMethodOptions options )
187+ {
188+ var messageRequest = request is RequestBase
189+ ? ( IInvokable ) this . requestCopier . Copy ( request ) !
190+ : request ;
191+ RuntimeClient . SendRequest ( reference , messageRequest , callback , options ) ;
192+ }
193+
189194 public object Cast ( IAddressable grain , Type grainInterface )
190195 {
191196 var grainId = grain . GetGrainId ( ) ;
0 commit comments