diff --git a/src/Orleans.Runtime/Activation/IGrainContextActivator.cs b/src/Orleans.Runtime/Activation/IGrainContextActivator.cs
index bd854a9ba9..3670a305bc 100644
--- a/src/Orleans.Runtime/Activation/IGrainContextActivator.cs
+++ b/src/Orleans.Runtime/Activation/IGrainContextActivator.cs
@@ -121,7 +121,7 @@ public interface IGrainContextActivatorProvider
/// if an appropriate activator was found, otherwise .
bool TryGet(GrainType grainType, [NotNullWhen(true)] out IGrainContextActivator activator);
}
-
+
///
/// Creates a grain context for the given grain address.
///
@@ -289,7 +289,7 @@ public void Configure(GrainType grainType, GrainProperties properties, GrainType
shared.SetComponent(component);
}
- component.MayInterleavePredicates.Add(_ => true);
+ component.MayInterleavePredicates.Add(ReentrantPredicate.Instance);
}
}
}
@@ -305,11 +305,11 @@ public MayInterleaveConfiguratorProvider(GrainClassMap grainClassMap)
public bool TryGetConfigurator(GrainType grainType, GrainProperties properties, out IConfigureGrainContext configurator)
{
- if (properties.Properties.TryGetValue(WellKnownGrainTypeProperties.MayInterleavePredicate, out var value)
+ if (properties.Properties.TryGetValue(WellKnownGrainTypeProperties.MayInterleavePredicate, out _)
&& _grainClassMap.TryGetGrainClass(grainType, out var grainClass))
{
var predicate = GetMayInterleavePredicate(grainClass);
- configurator = new MayInterleaveConfigurator(message => predicate(message.BodyObject as IInvokable));
+ configurator = new MayInterleaveConfigurator(predicate);
return true;
}
@@ -321,7 +321,7 @@ public bool TryGetConfigurator(GrainType grainType, GrainProperties properties,
/// Returns interleave predicate depending on whether class is marked with or not.
///
/// Grain class.
- private static Func GetMayInterleavePredicate(Type grainType)
+ private static IMayInterleavePredicate GetMayInterleavePredicate(Type grainType)
{
var attribute = grainType.GetCustomAttribute();
if (attribute is null)
@@ -329,12 +329,13 @@ private static Func GetMayInterleavePredicate(Type grainType)
return null;
}
+ // here
var callbackMethodName = attribute.CallbackMethodName;
- var method = grainType.GetMethod(callbackMethodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
+ var method = grainType.GetMethod(callbackMethodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
if (method == null)
{
throw new InvalidOperationException(
- $"Class {grainType.FullName} doesn't declare public static method " +
+ $"Class {grainType.FullName} doesn't declare public method " +
$"with name {callbackMethodName} specified in MayInterleave attribute");
}
@@ -345,18 +346,64 @@ private static Func GetMayInterleavePredicate(Type grainType)
throw new InvalidOperationException(
$"Wrong signature of callback method {callbackMethodName} " +
$"specified in MayInterleave attribute for grain class {grainType.FullName}. \n" +
- $"Expected: public static bool {callbackMethodName}(IInvokable req)");
+ $"Expected: public bool {callbackMethodName}(IInvokable req)");
+ }
+
+ if (method.IsStatic)
+ {
+ return new MayInterleaveStaticPredicate(method.CreateDelegate>());
}
- return method.CreateDelegate>();
+ var predicateType = typeof(MayInterleaveInstancedPredicate<>).MakeGenericType(grainType);
+ return (IMayInterleavePredicate)Activator.CreateInstance(predicateType, method);
}
}
+ internal interface IMayInterleavePredicate
+ {
+ bool Invoke(object instance, IInvokable bodyObject);
+ }
+
+ internal class ReentrantPredicate : IMayInterleavePredicate
+ {
+ private ReentrantPredicate()
+ {
+ }
+
+ public static ReentrantPredicate Instance { get; } = new();
+
+ public bool Invoke(object _, IInvokable bodyObject) => true;
+ }
+
+ internal class MayInterleaveStaticPredicate : IMayInterleavePredicate
+ {
+ private readonly Func _mayInterleavePredicate;
+
+ public MayInterleaveStaticPredicate(Func mayInterleavePredicate)
+ {
+ _mayInterleavePredicate = mayInterleavePredicate;
+ }
+
+ public bool Invoke(object _, IInvokable bodyObject) => _mayInterleavePredicate(bodyObject);
+ }
+
+ internal class MayInterleaveInstancedPredicate : IMayInterleavePredicate where T : class
+ {
+ private readonly Func _mayInterleavePredicate;
+
+ public MayInterleaveInstancedPredicate(MethodInfo mayInterleavePredicateInfo)
+ {
+ _mayInterleavePredicate = mayInterleavePredicateInfo.CreateDelegate>();
+ }
+
+ public bool Invoke(object instance, IInvokable bodyObject) => _mayInterleavePredicate(instance as T, bodyObject);
+ }
+
internal class MayInterleaveConfigurator : IConfigureGrainContext
{
- private readonly Func _mayInterleavePredicate;
+ private readonly IMayInterleavePredicate _mayInterleavePredicate;
- public MayInterleaveConfigurator(Func mayInterleavePredicate)
+ public MayInterleaveConfigurator(IMayInterleavePredicate mayInterleavePredicate)
{
_mayInterleavePredicate = mayInterleavePredicate;
}
@@ -376,12 +423,12 @@ public void Configure(IGrainContext context)
internal class GrainCanInterleave
{
- public List> MayInterleavePredicates { get; } = new List>();
- public bool MayInterleave(Message message)
+ public List MayInterleavePredicates { get; } = new List();
+ public bool MayInterleave(object instance, Message message)
{
foreach (var predicate in this.MayInterleavePredicates)
{
- if (predicate(message)) return true;
+ if (predicate.Invoke(instance, message.BodyObject as IInvokable)) return true;
}
return false;
diff --git a/src/Orleans.Runtime/Catalog/ActivationData.cs b/src/Orleans.Runtime/Catalog/ActivationData.cs
index 86fba03556..cd45fc5886 100644
--- a/src/Orleans.Runtime/Catalog/ActivationData.cs
+++ b/src/Orleans.Runtime/Catalog/ActivationData.cs
@@ -1016,7 +1016,7 @@ bool MayInvokeRequest(Message incoming)
{
try
{
- return canInterleave.MayInterleave(incoming);
+ return canInterleave.MayInterleave(GrainInstance, incoming);
}
catch (Exception exception)
{
diff --git a/test/Grains/TestGrainInterfaces/IReentrancyGrain.cs b/test/Grains/TestGrainInterfaces/IReentrancyGrain.cs
index 8a5c840f92..06a5a2dd11 100644
--- a/test/Grains/TestGrainInterfaces/IReentrancyGrain.cs
+++ b/test/Grains/TestGrainInterfaces/IReentrancyGrain.cs
@@ -23,7 +23,7 @@ public interface INonReentrantGrain : IGrainWithIntegerKey
Task SetSelf(INonReentrantGrain self);
}
- public interface IMayInterleavePredicateGrain : IGrainWithIntegerKey
+ public interface IMayInterleaveStaticPredicateGrain : IGrainWithIntegerKey
{
Task One(string arg); // this interleaves only when arg == "reentrant"
@@ -35,7 +35,22 @@ public interface IMayInterleavePredicateGrain : IGrainWithIntegerKey
Task SubscribeToStream();
Task PushToStream(string item);
- Task SetSelf(IMayInterleavePredicateGrain self);
+ Task SetSelf(IMayInterleaveStaticPredicateGrain self);
+ }
+
+ public interface IMayInterleaveInstancedPredicateGrain : IGrainWithIntegerKey
+ {
+ Task One(string arg); // this interleaves only when arg == "reentrant"
+
+ Task Two();
+ Task TwoReentrant();
+
+ Task Exceptional();
+
+ Task SubscribeToStream();
+ Task PushToStream(string item);
+
+ Task SetSelf(IMayInterleaveInstancedPredicateGrain self);
}
[Unordered]
diff --git a/test/Grains/TestGrains/ReentrantGrain.cs b/test/Grains/TestGrains/ReentrantGrain.cs
index 77310f7ba1..9d22e1b299 100644
--- a/test/Grains/TestGrains/ReentrantGrain.cs
+++ b/test/Grains/TestGrains/ReentrantGrain.cs
@@ -78,11 +78,11 @@ public Task SetSelf(INonReentrantGrain self)
}
[MayInterleave(nameof(MayInterleave))]
- public class MayInterleavePredicateGrain : Grain, IMayInterleavePredicateGrain
+ public class MayInterleaveStaticPredicateGrain : Grain, IMayInterleaveStaticPredicateGrain
{
private readonly ILogger logger;
- public MayInterleavePredicateGrain(ILoggerFactory loggerFactory)
+ public MayInterleaveStaticPredicateGrain(ILoggerFactory loggerFactory)
{
this.logger = loggerFactory.CreateLogger($"{this.GetType().Name}-{this.IdentityString}");
}
@@ -111,9 +111,9 @@ public static bool MayInterleave(IInvokable req)
static object UnwrapImmutable(object item) => item is Immutable