Skip to content

Commit

Permalink
Change to use a Linq expression for constructing the FieldCrawler, si…
Browse files Browse the repository at this point in the history
…nce Reflection is slower than Linq and is hundreds of times slower when you cache the Linq compiled code.

Since we tight loop over the constructor for each field we read, that is a HUGE amount of time spent in the reflection library.
  • Loading branch information
arontsang committed Dec 12, 2013
1 parent 61ee49b commit 8559845
Showing 1 changed file with 41 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace scSearchContrib.Crawler.FieldCrawlers
{
using System;
using System.Collections.Generic;

using Sitecore.Collections;
Expand Down Expand Up @@ -36,7 +37,7 @@ public static IEnumerable<string> GetFieldCrawlerValues(Field field, SafeDiction

if (!string.IsNullOrEmpty(fieldCrawlerType))
{
var fieldCrawler = ReflectionUtil.CreateObject(fieldCrawlerType, new object[] { field });
var fieldCrawler = GetFieldCrawlerByType(fieldCrawlerType, field);

if (fieldCrawler is IMultivaluedFieldCrawler)
{
Expand All @@ -52,5 +53,44 @@ public static IEnumerable<string> GetFieldCrawlerValues(Field field, SafeDiction

return new[] { new DefaultFieldCrawler(field).GetValue() };
}

private static object GetFieldCrawlerByType(string fieldCrawlerType, Field field)
{
Func<Field, object> constructor;
// We could put in interlocks into the below code. However it is idempotent.
// Yes it will be non-optimal if multiple threads access the same type at the same time
// However afterwards, we will have better perf, when there is no locking.
// Plus its simplier :)
if (_compiledExpressions.TryGetValue(fieldCrawlerType, out constructor) == false)
{
_compiledExpressions[fieldCrawlerType] = constructor = ConstructorExpression(fieldCrawlerType);
}
return constructor(field);
}

// Cache the IL for constructing FieldCrawlers
// Expression compile is expensive. But still SOOO much cheaper than reflection that it is replacing.
private readonly static Dictionary<string, Func<Field, object>> _compiledExpressions = new Dictionary<string, Func<Field, object>>();


// Create IL to run the constructor.
private static Func<Field, object> ConstructorExpression(string typeName)
{
var type = Type.GetType(typeName);
if (type == null)
return field => null;

var constructor = type.GetConstructor(new[] {typeof (Field)});

if (constructor == null)
return field => null;

var paramExpression = System.Linq.Expressions.Expression.Parameter(typeof (Field), "field");
var newExpression = System.Linq.Expressions.Expression.New(constructor, paramExpression);
var lambda = System.Linq.Expressions.Expression.Lambda<Func<Field, object>>(newExpression, paramExpression);

return lambda.Compile();

}
}
}

0 comments on commit 8559845

Please sign in to comment.