From 74fdb67920abc56ad98d4069eef5569a2f1262a3 Mon Sep 17 00:00:00 2001 From: Lucas Pimentel-Ordyna Date: Wed, 17 Jul 2019 15:29:27 -0400 Subject: [PATCH] cache reflected types --- .../StackExchange.Redis/RedisBatch.cs | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Datadog.Trace.ClrProfiler.Managed/Integrations/StackExchange.Redis/RedisBatch.cs b/src/Datadog.Trace.ClrProfiler.Managed/Integrations/StackExchange.Redis/RedisBatch.cs index b0ae929f308d..1cd6b37da43c 100644 --- a/src/Datadog.Trace.ClrProfiler.Managed/Integrations/StackExchange.Redis/RedisBatch.cs +++ b/src/Datadog.Trace.ClrProfiler.Managed/Integrations/StackExchange.Redis/RedisBatch.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Concurrent; +using System.Reflection; using System.Threading.Tasks; using Datadog.Trace.ClrProfiler.Emit; @@ -16,6 +18,15 @@ public static class RedisBatch private const string Major1 = "1"; private const string Major2 = "2"; + private static readonly ConcurrentDictionary ProcessorTypes = new ConcurrentDictionary(); + + private static Assembly _redisAssembly; + private static Type _redisBaseType; + private static Type _messageType; + private static Type _processorOpenType; + private static Type _serverType; + private static Type _batchType; + /// /// Execute an asynchronous redis operation. /// @@ -62,24 +73,33 @@ public static object ExecuteAsync(object redisBase, object message, object pr private static async Task ExecuteAsyncInternal(object redisBase, object message, object processor, object server, OpCodeValue callOpCode) { var thisType = redisBase.GetType(); + + if (_redisAssembly == null) + { + // get these only once and cache them, + // no need for locking, race conditions are no a problem + _redisAssembly = thisType.Assembly; + _redisBaseType = _redisAssembly.GetType("StackExchange.Redis.RedisBase"); + _batchType = _redisAssembly.GetType("StackExchange.Redis.RedisBatch"); + _messageType = _redisAssembly.GetType("StackExchange.Redis.Message"); + _processorOpenType = _redisAssembly.GetType("StackExchange.Redis.ResultProcessor`1"); + _serverType = _redisAssembly.GetType("StackExchange.Redis.ServerEndPoint"); + } + + // cache one processor type for each type of T var genericType = typeof(T); - var asm = thisType.Assembly; - var redisBaseType = asm.GetType("StackExchange.Redis.RedisBase"); - var batchType = asm.GetType("StackExchange.Redis.RedisBatch"); - var messageType = asm.GetType("StackExchange.Redis.Message"); - var processorType = asm.GetType("StackExchange.Redis.ResultProcessor`1").MakeGenericType(genericType); - var serverType = asm.GetType("StackExchange.Redis.ServerEndPoint"); + var processorType = ProcessorTypes.GetOrAdd(genericType, t => _processorOpenType.MakeGenericType(t)); var originalMethod = Emit.DynamicMethodBuilder>> .GetOrCreateMethodCallDelegate( - redisBaseType, + _redisBaseType, methodName: "ExecuteAsync", callOpCode, - methodParameterTypes: new[] { messageType, processorType, serverType }, + methodParameterTypes: new[] { _messageType, processorType, _serverType }, methodGenericArguments: new[] { genericType }); // we only trace RedisBatch methods here - if (thisType == batchType) + if (thisType == _batchType) { using (var scope = CreateScope(redisBase, message)) {