Skip to content

Commit

Permalink
Added locks for caching when running on multiple threads
Browse files Browse the repository at this point in the history
  • Loading branch information
eswann committed Jul 31, 2014
1 parent e326a12 commit 67e0942
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 55 deletions.
1 change: 1 addition & 0 deletions src/Fpr.Tests/Fpr.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<Compile Include="WhenMappingWithInstance.cs" />
<Compile Include="WhenPerformingDestinationTransforms.cs" />
<Compile Include="WhenProjecting.cs" />
<Compile Include="WhenRunningOnMultipleThreads.cs" />
<Compile Include="WhenUsingNonDefaultConstructor.cs" />
<Compile Include="WhenUsingTypeResolvers.cs" />
<Compile Include="WhenUsingValueResolvers.cs" />
Expand Down
96 changes: 96 additions & 0 deletions src/Fpr.Tests/WhenRunningOnMultipleThreads.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Fpr.Tests
{
[TestFixture]
public class WhenRunningOnMultipleThreads
{

[SetUp]
public void Setup()
{
TypeAdapterConfig<Customer, CustomerDTO>.Clear();
TypeAdapterConfig<Address, AddressDTO>.Clear();
}

[Test]
public void Can_Set_Up_Mapping_On_Multiple_Threads()
{
Parallel.For(1, 5, x => TypeAdapterConfig<Customer, CustomerDTO>.NewConfig());
}

[Test]
public void Can_Set_Up_Adapt_On_Multiple_Threads()
{
Parallel.For(1, 5, x => TypeAdapter.Adapt<Customer, CustomerDTO>(GetCustomer()));
}


private static Customer GetCustomer()
{
Customer c = new Customer()
{
Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." },
HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." },
Id = 1,
Name = "Kıvanç",
Credit = 234.7m,
WorkAddresses = new List<Address>() {
new Address() { City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad." },
new Address() { City = "izmir", Country = "turkey", Id = 6, Street = "konak" }
},
Addresses = new List<Address>() {
new Address() { City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad." },
new Address() { City = "izmir", Country = "turkey", Id = 4, Street = "konak" }
}.ToArray()
};

return c;
}


#region Test Classes

public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
}

public class AddressDTO
{
public int Id { get; set; }
public string City { get; set; }
public string Country { get; set; }
}

public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public decimal? Credit { get; set; }
public Address Address { get; set; }
public Address HomeAddress { get; set; }
public Address[] Addresses { get; set; }
public ICollection<Address> WorkAddresses { get; set; }
}

public class CustomerDTO
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public AddressDTO HomeAddress { get; set; }
public AddressDTO[] Addresses { get; set; }
public List<AddressDTO> WorkAddresses { get; set; }
public string AddressCity { get; set; }
}

#endregion

}
}
127 changes: 72 additions & 55 deletions src/Fpr/Utils/PropertyCaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace Fpr.Utils
{
public static class PropertyCaller<TClass, TReturn> where TClass : class
{
private static readonly object _getterLock = new object();
private static readonly object _setterLock = new object();

private static readonly Dictionary<Type, Dictionary<Type, Dictionary<string, GenGetter>>> _getterCache =
new Dictionary<Type, Dictionary<Type, Dictionary<string, GenGetter>>>();

Expand Down Expand Up @@ -58,31 +61,33 @@ public static GenGetter CreateGetMethod(PropertyInfo pi)
//Create the delegate and return it
var genGetter = (GenGetter)getter.CreateDelegate(typeof(GenGetter));

//Cache the delegate for future use.
Dictionary<string, GenGetter> tempPropDict;

if (!_getterCache.ContainsKey(classType))
lock (_getterLock)
{
tempPropDict = new Dictionary<string, GenGetter> {{propertyName, genGetter}};

var tempDict = new Dictionary<Type, Dictionary<string, GenGetter>> {{returnType, tempPropDict}};
//Cache the delegate for future use.
Dictionary<string, GenGetter> tempPropDict;

_getterCache.Add(classType, tempDict);
}
else
{
if (!_getterCache[classType].ContainsKey(returnType))
if (!_getterCache.ContainsKey(classType))
{
tempPropDict = new Dictionary<string, GenGetter> {{propertyName, genGetter}};
_getterCache[classType].Add(returnType, tempPropDict);

var tempDict = new Dictionary<Type, Dictionary<string, GenGetter>> {{returnType, tempPropDict}};

_getterCache.Add(classType, tempDict);
}
else
{
if (!_getterCache[classType][returnType].ContainsKey(propertyName))
_getterCache[classType][returnType].Add(propertyName, genGetter);
if (!_getterCache[classType].ContainsKey(returnType))
{
tempPropDict = new Dictionary<string, GenGetter> {{propertyName, genGetter}};
_getterCache[classType].Add(returnType, tempPropDict);
}
else
{
if (!_getterCache[classType][returnType].ContainsKey(propertyName))
_getterCache[classType][returnType].Add(propertyName, genGetter);
}
}
}

//Return delegate to the caller.
return genGetter;

Expand Down Expand Up @@ -139,29 +144,32 @@ public static GenSetter CreateSetMethod(PropertyInfo pi)
//Create the delegate
var genSetter = (GenSetter)setter.CreateDelegate(typeof(GenSetter));

//Cache the delegate for future use.
Dictionary<string, GenSetter> tempPropDict;

if (!_setterCache.ContainsKey(classType))
lock (_setterLock)
{
tempPropDict = new Dictionary<string, GenSetter> {{propertyName, genSetter}};
//Cache the delegate for future use.
Dictionary<string, GenSetter> tempPropDict;

var tempDict = new Dictionary<Type, Dictionary<string, GenSetter>> {{returnType, tempPropDict}};

_setterCache.Add(classType, tempDict);
}
else
{
if (!_setterCache[classType].ContainsKey(returnType))
if (!_setterCache.ContainsKey(classType))
{
tempPropDict = new Dictionary<string, GenSetter> {{propertyName, genSetter}};

_setterCache[classType].Add(returnType, tempPropDict);
var tempDict = new Dictionary<Type, Dictionary<string, GenSetter>> {{returnType, tempPropDict}};

_setterCache.Add(classType, tempDict);
}
else
{
if (!_setterCache[classType][returnType].ContainsKey(propertyName))
_setterCache[classType][returnType].Add(propertyName, genSetter);
if (!_setterCache[classType].ContainsKey(returnType))
{
tempPropDict = new Dictionary<string, GenSetter> {{propertyName, genSetter}};

_setterCache[classType].Add(returnType, tempPropDict);
}
else
{
if (!_setterCache[classType][returnType].ContainsKey(propertyName))
_setterCache[classType][returnType].Add(propertyName, genSetter);
}
}
}
//Return delegate to the caller.
Expand All @@ -175,6 +183,9 @@ public static class PropertyCaller<T>
public delegate void GenSetter(T target, Object value);
public delegate Object GenGetter(T target);

private static readonly object _getterLock = new object();
private static readonly object _setterLock = new object();

private static readonly Dictionary<Type, Dictionary<Type, Dictionary<string, GenGetter>>> _getterCache = new Dictionary<Type, Dictionary<Type, Dictionary<string, GenGetter>>>();
private static readonly Dictionary<Type, Dictionary<Type, Dictionary<string, GenSetter>>> _setterCache = new Dictionary<Type, Dictionary<Type, Dictionary<string, GenSetter>>>();

Expand Down Expand Up @@ -218,25 +229,28 @@ public static GenGetter CreateGetMethod(PropertyInfo pi)
//Create the delegate and return it
var genGetter = (GenGetter)getter.CreateDelegate(typeof(GenGetter));

Dictionary<string, GenGetter> tempPropDict;
if (!_getterCache.ContainsKey(classType))
lock (_getterLock)
{
tempPropDict = new Dictionary<string, GenGetter> {{propName, genGetter}};
var tempDict = new Dictionary<Type, Dictionary<string, GenGetter>> {{propType, tempPropDict}};
_getterCache.Add(classType, tempDict);
}
else
{
if (!_getterCache[classType].ContainsKey(propType))
Dictionary<string, GenGetter> tempPropDict;
if (!_getterCache.ContainsKey(classType))
{
tempPropDict = new Dictionary<string, GenGetter> {{propName, genGetter}};
_getterCache[classType].Add(propType, tempPropDict);
var tempDict = new Dictionary<Type, Dictionary<string, GenGetter>> {{propType, tempPropDict}};
_getterCache.Add(classType, tempDict);
}
else
{
if (!_getterCache[classType][propType].ContainsKey(propName))
if (!_getterCache[classType].ContainsKey(propType))
{
tempPropDict = new Dictionary<string, GenGetter> {{propName, genGetter}};
_getterCache[classType].Add(propType, tempPropDict);
}
else
{
_getterCache[classType][propType].Add(propName, genGetter);
if (!_getterCache[classType][propType].ContainsKey(propName))
{
_getterCache[classType][propType].Add(propName, genGetter);
}
}
}
}
Expand Down Expand Up @@ -290,25 +304,28 @@ public static GenSetter CreateSetMethod(PropertyInfo pi)
//Create the delegate and return it
var genSetter = (GenSetter)setter.CreateDelegate(typeof(GenSetter));

Dictionary<string, GenSetter> tempPropDict;
if (!_setterCache.ContainsKey(classType))
{
tempPropDict = new Dictionary<string, GenSetter> {{propName, genSetter}};
var tempDict = new Dictionary<Type, Dictionary<string, GenSetter>> {{propType, tempPropDict}};
_setterCache.Add(classType, tempDict);
}
else
lock (_setterLock)
{
if (!_setterCache[classType].ContainsKey(propType))
Dictionary<string, GenSetter> tempPropDict;
if (!_setterCache.ContainsKey(classType))
{
tempPropDict = new Dictionary<string, GenSetter> {{propName, genSetter}};
_setterCache[classType].Add(propType, tempPropDict);
var tempDict = new Dictionary<Type, Dictionary<string, GenSetter>> {{propType, tempPropDict}};
_setterCache.Add(classType, tempDict);
}
else
{
if (!_setterCache[classType][propType].ContainsKey(propName))
if (!_setterCache[classType].ContainsKey(propType))
{
tempPropDict = new Dictionary<string, GenSetter> {{propName, genSetter}};
_setterCache[classType].Add(propType, tempPropDict);
}
else
{
_setterCache[classType][propType].Add(propName, genSetter);
if (!_setterCache[classType][propType].ContainsKey(propName))
{
_setterCache[classType][propType].Add(propName, genSetter);
}
}
}
}
Expand Down

0 comments on commit 67e0942

Please sign in to comment.