Skip to content

Commit

Permalink
cache reflected types
Browse files Browse the repository at this point in the history
  • Loading branch information
lucaspimentel committed Jul 17, 2019
1 parent 40e8d59 commit 74fdb67
Showing 1 changed file with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Threading.Tasks;
using Datadog.Trace.ClrProfiler.Emit;

Expand All @@ -16,6 +18,15 @@ public static class RedisBatch
private const string Major1 = "1";
private const string Major2 = "2";

private static readonly ConcurrentDictionary<Type, Type> ProcessorTypes = new ConcurrentDictionary<Type, Type>();

private static Assembly _redisAssembly;
private static Type _redisBaseType;
private static Type _messageType;
private static Type _processorOpenType;
private static Type _serverType;
private static Type _batchType;

/// <summary>
/// Execute an asynchronous redis operation.
/// </summary>
Expand Down Expand Up @@ -62,24 +73,33 @@ public static object ExecuteAsync<T>(object redisBase, object message, object pr
private static async Task<T> ExecuteAsyncInternal<T>(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<Func<object, object, object, object, Task<T>>>
.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))
{
Expand Down

0 comments on commit 74fdb67

Please sign in to comment.