mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
#19476: Refactoring DefaultOrchardEventBus for performance.
Added event handler filtering using Autofac's IIndex<K,V> and named registrations. Replaced slow MethodInfo.Invoke with very fast, strongly-typed delegates. Each delegate is created at first usage and cached. Updated unit tests to take changes into account. Work Item: 19476 --HG-- branch : 1.x
This commit is contained in:
@@ -20,8 +20,15 @@ namespace Orchard.Tests.Events {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>();
|
||||
builder.RegisterType<StubExceptionPolicy>().As<IExceptionPolicy>();
|
||||
builder.RegisterType<StubEventHandler2>().As<IEventHandler>();
|
||||
builder.RegisterInstance(_eventHandler).As<IEventHandler>();
|
||||
|
||||
builder.RegisterType<StubEventHandler2>()
|
||||
.Named(typeof(ITestEventHandler).Name.ToLowerInvariant(), typeof(IEventHandler))
|
||||
.Named(typeof(IEventHandler).Name.ToLowerInvariant(), typeof(IEventHandler))
|
||||
.WithMetadata("Interfaces", typeof(StubEventHandler2).GetInterfaces().ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase));
|
||||
builder.RegisterInstance(_eventHandler)
|
||||
.Named(typeof(ITestEventHandler).Name.ToLowerInvariant(), typeof(IEventHandler))
|
||||
.Named(typeof(IEventHandler).Name.ToLowerInvariant(), typeof(IEventHandler))
|
||||
.WithMetadata("Interfaces", typeof(StubEventHandler).GetInterfaces().ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
_container = builder.Build();
|
||||
_eventBus = _container.Resolve<IEventBus>();
|
||||
|
@@ -81,7 +81,13 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
}
|
||||
|
||||
if (typeof(IEventHandler).IsAssignableFrom(item.Type)) {
|
||||
registration = registration.As(typeof(IEventHandler));
|
||||
var interfaces = item.Type.GetInterfaces();
|
||||
foreach (var interfaceType in interfaces) {
|
||||
// Register named instance for each interface, for efficient filtering withing event bus
|
||||
registration = registration.Named(interfaceType.Name.ToLowerInvariant(), typeof (IEventHandler));
|
||||
}
|
||||
// Keep interfaces in metadata for performance
|
||||
registration = registration.WithMetadata("Interfaces", interfaces.ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
foreach (var parameter in item.Parameters) {
|
||||
|
@@ -4,16 +4,19 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Autofac.Features.Indexed;
|
||||
using Autofac.Features.Metadata;
|
||||
using Orchard.Exceptions;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Events {
|
||||
public class DefaultOrchardEventBus : IEventBus {
|
||||
private readonly Func<IEnumerable<IEventHandler>> _eventHandlers;
|
||||
private readonly IIndex<string, IEnumerable<Meta<IEventHandler>>> _eventHandlers;
|
||||
private readonly IExceptionPolicy _exceptionPolicy;
|
||||
private static readonly ConcurrentDictionary<string, MethodInfo> _interfaceMethodsCache = new ConcurrentDictionary<string, MethodInfo>();
|
||||
private static readonly ConcurrentDictionary<string, Tuple<ParameterInfo[], Func<IEventHandler, object[], object>>> _delegateCache = new ConcurrentDictionary<string, Tuple<ParameterInfo[], Func<IEventHandler, object[], object>>>();
|
||||
|
||||
public DefaultOrchardEventBus(Func<IEnumerable<IEventHandler>> eventHandlers, IExceptionPolicy exceptionPolicy) {
|
||||
public DefaultOrchardEventBus(IIndex<string, IEnumerable<Meta<IEventHandler>>> eventHandlers, IExceptionPolicy exceptionPolicy)
|
||||
{
|
||||
_eventHandlers = eventHandlers;
|
||||
_exceptionPolicy = exceptionPolicy;
|
||||
T = NullLocalizer.Instance;
|
||||
@@ -34,7 +37,7 @@ namespace Orchard.Events {
|
||||
string interfaceName = parameters[0];
|
||||
string methodName = parameters[1];
|
||||
|
||||
var eventHandlers = _eventHandlers();
|
||||
var eventHandlers = _eventHandlers[interfaceName.ToLowerInvariant()];
|
||||
foreach (var eventHandler in eventHandlers) {
|
||||
IEnumerable returnValue;
|
||||
if (TryNotifyHandler(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue)) {
|
||||
@@ -47,7 +50,7 @@ namespace Orchard.Events {
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryNotifyHandler(IEventHandler eventHandler, string messageName, string interfaceName, string methodName, IDictionary<string, object> eventData, out IEnumerable returnValue) {
|
||||
private bool TryNotifyHandler(Meta<IEventHandler> eventHandler, string messageName, string interfaceName, string methodName, IDictionary<string, object> eventData, out IEnumerable returnValue) {
|
||||
try {
|
||||
return TryInvoke(eventHandler, interfaceName, methodName, eventData, out returnValue);
|
||||
}
|
||||
@@ -61,31 +64,34 @@ namespace Orchard.Events {
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryInvoke(IEventHandler eventHandler, string interfaceName, string methodName, IDictionary<string, object> arguments, out IEnumerable returnValue) {
|
||||
Type type = eventHandler.GetType();
|
||||
foreach (var interfaceType in type.GetInterfaces()) {
|
||||
if (String.Equals(interfaceType.Name, interfaceName, StringComparison.OrdinalIgnoreCase)) {
|
||||
return TryInvokeMethod(eventHandler, interfaceType, methodName, arguments, out returnValue);
|
||||
}
|
||||
private static bool TryInvoke(Meta<IEventHandler> eventHandler, string interfaceName, string methodName, IDictionary<string, object> arguments, out IEnumerable returnValue) {
|
||||
var matchingInterfaces = ((ILookup<string, Type>)eventHandler.Metadata["Interfaces"])[interfaceName];
|
||||
foreach (var interfaceType in matchingInterfaces) {
|
||||
return TryInvokeMethod(eventHandler.Value, interfaceType, methodName, arguments, out returnValue);
|
||||
}
|
||||
returnValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryInvokeMethod(IEventHandler eventHandler, Type interfaceType, string methodName, IDictionary<string, object> arguments, out IEnumerable returnValue) {
|
||||
MethodInfo method = _interfaceMethodsCache.GetOrAdd(String.Concat(eventHandler.GetType().FullName + "_" + interfaceType.Name, "_", methodName, "_", String.Join("_", arguments.Keys)), GetMatchingMethod(eventHandler, interfaceType, methodName, arguments));
|
||||
var key = String.Concat(eventHandler.GetType().FullName + "_" + interfaceType.Name, "_", methodName, "_", String.Join("_", arguments.Keys));
|
||||
var cachedDelegate = _delegateCache.GetOrAdd(key, k => {
|
||||
var method = GetMatchingMethod(eventHandler, interfaceType, methodName, arguments);
|
||||
return method != null
|
||||
? Tuple.Create(method.GetParameters(), DelegateHelper.CreateDelegate<IEventHandler>(interfaceType, method))
|
||||
: null;
|
||||
});
|
||||
|
||||
if (cachedDelegate != null) {
|
||||
var args = cachedDelegate.Item1.Select(methodParameter => arguments[methodParameter.Name]).ToArray();
|
||||
var result = cachedDelegate.Item2(eventHandler, args);
|
||||
|
||||
if (method != null) {
|
||||
var parameters = new List<object>();
|
||||
foreach (var methodParameter in method.GetParameters()) {
|
||||
parameters.Add(arguments[methodParameter.Name]);
|
||||
}
|
||||
var result = method.Invoke(eventHandler, parameters.ToArray());
|
||||
returnValue = result as IEnumerable;
|
||||
if (returnValue == null && result != null)
|
||||
returnValue = new[] { result };
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
returnValue = null;
|
||||
return false;
|
||||
}
|
||||
|
174
src/Orchard/Events/DelegateHelper.cs
Normal file
174
src/Orchard/Events/DelegateHelper.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Orchard.Events {
|
||||
public static class DelegateHelper {
|
||||
public static Func<T, object[], object> CreateDelegate<T>(MethodInfo method) {
|
||||
return CreateDelegate<T>(typeof(T), method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a strongly-typed dynamic delegate that represents a given method on a given target type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Provided method must be valid for the type provided as targetType.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the delegate target (first argument) object. Needs to be assignable from the type provided as targetType parameter.</typeparam>
|
||||
/// <param name="targetType">Delegate target type.</param>
|
||||
/// <param name="method">Method that the delegate represents.</param>
|
||||
/// <returns>Strongly-typed delegate representing the given method.
|
||||
/// First argument is the target of the delegate.
|
||||
/// Second argument describes call arguments.
|
||||
/// </returns>
|
||||
public static Func<T, object[], object> CreateDelegate<T>(Type targetType, MethodInfo method) {
|
||||
var parameters = method.ReturnType == typeof(void)
|
||||
? new[] { targetType }.Concat(method.GetParameters().Select(p => p.ParameterType)).ToArray()
|
||||
: new[] { targetType }.Concat(method.GetParameters().Select(p => p.ParameterType)).Concat(new[] { method.ReturnType }).ToArray();
|
||||
|
||||
// First fetch the generic form
|
||||
MethodInfo genericHelper = method.ReturnType == typeof(void)
|
||||
? typeof(DelegateHelper).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).First(m => m.Name == "BuildAction" && m.GetGenericArguments().Count() == parameters.Length)
|
||||
: typeof(DelegateHelper).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).First(m => m.Name == "BuildFunc" && m.GetGenericArguments().Count() == parameters.Length);
|
||||
|
||||
// Now supply the type arguments
|
||||
MethodInfo constructedHelper = genericHelper.MakeGenericMethod(parameters);
|
||||
|
||||
// Now call it. The null argument is because it's a static method.
|
||||
object ret = constructedHelper.Invoke(null, new object[] { method });
|
||||
return (Func<T, object[], object>)ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, TRet>)Delegate.CreateDelegate(typeof(Func<T, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, T5, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, T6, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, T6, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, T5, T6, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, T6, T7, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, T6, T7, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, T5, T6, T7, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, T6, T7, T8, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, T5, T6, T7, T8, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>)Delegate.CreateDelegate(typeof(Func<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7], (T9)p[8]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildFunc<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(MethodInfo method) {
|
||||
var func = (Func<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>)Delegate.CreateDelegate(typeof(Func<T, TRet>), method);
|
||||
Func<object, object[], object> ret = (target, p) => func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7], (T9)p[8], (T10)p[9]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T>(MethodInfo method) {
|
||||
var func = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1>(MethodInfo method) {
|
||||
var func = (Action<T, T1>)Delegate.CreateDelegate(typeof(Action<T, T1>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2>)Delegate.CreateDelegate(typeof(Action<T, T1, T2>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4, T5>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5, T6>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5, T6>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4, T5, T6>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5, T6, T7>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5, T6, T7>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4, T5, T6, T7>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5, T6, T7, T8>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5, T6, T7, T8>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4, T5, T6, T7, T8>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>)Delegate.CreateDelegate(typeof(Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7], (T9)p[8]); return null; };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Func<object, object[], object> BuildAction<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(MethodInfo method) {
|
||||
var func = (Action<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>)Delegate.CreateDelegate(typeof(Action<T>), method);
|
||||
Func<object, object[], object> ret = (target, p) => { func((T)target, (T1)p[0], (T2)p[1], (T3)p[2], (T4)p[3], (T5)p[4], (T6)p[5], (T7)p[6], (T8)p[7], (T9)p[8], (T10)p[9]); return null; };
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@@ -227,6 +227,7 @@
|
||||
<Compile Include="Environment\WorkContextImplementation.cs" />
|
||||
<Compile Include="Environment\WorkContextModule.cs" />
|
||||
<Compile Include="Environment\WorkContextProperty.cs" />
|
||||
<Compile Include="Events\DelegateHelper.cs" />
|
||||
<Compile Include="Exceptions\DefaultExceptionPolicy.cs" />
|
||||
<Compile Include="Exceptions\ExceptionExtensions.cs" />
|
||||
<Compile Include="Exceptions\Filters\UnhandledExceptionFilter.cs" />
|
||||
|
Reference in New Issue
Block a user