Skip to content

Commit

Permalink
Minor code refactorization and further thread-safety improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
alien-mcl committed Jun 25, 2016
1 parent 62fcdec commit ab8f8e5
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 49 deletions.
42 changes: 37 additions & 5 deletions RomanticWeb/EntityContextFactory.cs
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand All @@ -23,8 +24,9 @@ public class EntityContextFactory : IEntityContextFactory, IComponentRegistryFac
{
private static readonly object Locker = new object();
private readonly IServiceContainer _container;
private readonly IList<Scope> _trackedScopes = new List<Scope>();
private IDictionary<Scope, Scope> _trackedScopes;
private bool _disposed;
private bool _threadSafe;

/// <summary>Initializes a new instance of <see cref="EntityContextFactory"/> class.</summary>
public EntityContextFactory() : this(new ServiceContainer())
Expand All @@ -33,6 +35,7 @@ public EntityContextFactory() : this(new ServiceContainer())

internal EntityContextFactory(IServiceContainer container)
{
_trackedScopes = new Dictionary<Scope, Scope>();
_container = container;
_container.RegisterAssembly("RomanticWeb.dll");
_container.Register<IEntityContextFactory>(f => this);
Expand Down Expand Up @@ -66,9 +69,37 @@ internal EntityContextFactory(IServiceContainer container)
/// <inheritdoc />
public IResourceResolutionStrategy ResourceResolutionStrategy { get { return _container.GetInstance<IResourceResolutionStrategy>(); } }

internal IList<Scope> TrackedScopes { get { return _trackedScopes; } }
internal IEnumerable<Scope> TrackedScopes { get { return _trackedScopes.Values; } }

internal bool ThreadSafe { get; set; }
internal bool ThreadSafe
{
get
{
return _threadSafe;
}

set
{
if (_threadSafe == value)
{
return;
}

if (_trackedScopes.Count > 0)
{
throw new InvalidOperationException("Cannot set thread-safety flag. EntityContextFactory already in use.");
}

if (_threadSafe = value)
{
_trackedScopes = new ConcurrentDictionary<Scope, Scope>();
}
else
{
_trackedScopes = new Dictionary<Scope, Scope>();
}
}
}

internal bool TrackChanges { get; set; }

Expand Down Expand Up @@ -110,7 +141,7 @@ public IEntityContext CreateContext()
lock (Locker)
{
var scope = _container.BeginScope();
TrackedScopes.Add(scope);
_trackedScopes.Add(scope, scope);
var context = _container.GetInstance<IEntityContext>();
context.TrackChanges = TrackChanges;
if (context.Store is IThreadSafeEntityStore)
Expand Down Expand Up @@ -217,8 +248,9 @@ public void Dispose()
return;
}

foreach (var scope in TrackedScopes.ToList())
while (_trackedScopes.Count > 0)
{
var scope = _trackedScopes.Values.First();
scope.Dispose();
}

Expand Down
25 changes: 12 additions & 13 deletions RomanticWeb/Linq/EntityQueryVisitor.cs
Expand Up @@ -420,28 +420,27 @@ protected override System.Linq.Expressions.Expression VisitMemberExpression(Syst
{
return VisitEntityId(new EntityIdentifierExpression(expression, target));
}
else
{
ExceptionHelper.ThrowInvalidCastException(typeof(IEntity), expression.Member.DeclaringType);
}

ExceptionHelper.ThrowInvalidCastException(typeof(IEntity), expression.Member.DeclaringType);
}
else if ((typeof(IEntity).IsAssignableFrom(expression.Member.DeclaringType)) && (expression.Member is PropertyInfo))
else if (expression.Member is PropertyInfo)
{
IPropertyMapping propertyMapping = _entityContext.Mappings.FindPropertyMapping((PropertyInfo)expression.Member);
Remotion.Linq.Clauses.FromClauseBase target = GetMemberTarget(expression);
if ((propertyMapping != null) && (target != null))
if (propertyMapping != null)
{
return VisitEntityProperty(new EntityPropertyExpression(expression, propertyMapping, target, (_itemNameOverride != null ? _itemNameOverride : expression.Member.Name)));
Remotion.Linq.Clauses.FromClauseBase target = GetMemberTarget(expression);
if (target != null)
{
return VisitEntityProperty(new EntityPropertyExpression(expression, propertyMapping, target, (_itemNameOverride ?? expression.Member.Name)));
}

ExceptionHelper.ThrowInvalidCastException(typeof(IEntity), expression.Member.DeclaringType);
}
else
{
ExceptionHelper.ThrowInvalidCastException(typeof(IEntity), expression.Member.DeclaringType);
return VisitPropertyExpression(expression);
}
}
else if (expression.Member is PropertyInfo)
{
return VisitPropertyExpression(expression);
}

return base.VisitMemberExpression(expression);
}
Expand Down
63 changes: 33 additions & 30 deletions RomanticWeb/Mapping/RdfTypeCache.cs
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using NullGuard;
Expand All @@ -13,18 +14,18 @@ namespace RomanticWeb.Mapping
/// </summary>
public class RdfTypeCache : IRdfTypeCache
{
private readonly IDictionary<string, IEnumerable<Type>> _cache;
private readonly IDictionary<Type, IList<IClassMapping>> _classMappings;
private readonly IDictionary<Type, ISet<Type>> _directlyDerivingTypes;
private IDictionary<string, IEnumerable<Type>> _cache;
private IDictionary<Type, IList<IClassMapping>> _classMappings;
private IDictionary<Type, ISet<Type>> _directlyDerivingTypes;

/// <summary>
/// Initializes a new instance of the <see cref="RdfTypeCache"/> class.
/// </summary>
public RdfTypeCache()
{
_classMappings = new Dictionary<Type, IList<IClassMapping>>();
_directlyDerivingTypes = new Dictionary<Type, ISet<Type>>();
_cache = new Dictionary<string, IEnumerable<Type>>();
_classMappings = new ConcurrentDictionary<Type, IList<IClassMapping>>();
_directlyDerivingTypes = new ConcurrentDictionary<Type, ISet<Type>>();
_cache = new ConcurrentDictionary<string, IEnumerable<Type>>();
}

/// <inheridoc/>
Expand All @@ -40,40 +41,42 @@ public IEnumerable<Type> GetMostDerivedMappedTypes(IEnumerable<Uri> entityTypes,
IEnumerable<Type> cached;
var classList = entityTypes as Uri[] ?? entityTypes.ToArray();
string cacheKey = requestedType + ";" + String.Join(";", classList.Select(item => item.ToString()));
if (!_cache.TryGetValue(cacheKey, out cached))
if (_cache.TryGetValue(cacheKey, out cached))
{
if ((classList.Any()) && (_directlyDerivingTypes.ContainsKey(requestedType)))
return cached;
}

if ((!classList.Any()) || (!_directlyDerivingTypes.ContainsKey(requestedType)))
{
return _cache[cacheKey] = selectedTypes.GetMostDerivedTypes();
}

var childTypesToCheck = new Queue<Type>(_directlyDerivingTypes[requestedType]);
while (childTypesToCheck.Any())
{
Type potentialMatch = childTypesToCheck.Dequeue();

if (_directlyDerivingTypes.ContainsKey(potentialMatch))
{
var childTypesToCheck = new Queue<Type>(_directlyDerivingTypes[requestedType]);
while (childTypesToCheck.Any())
foreach (var child in _directlyDerivingTypes[potentialMatch])
{
Type potentialMatch = childTypesToCheck.Dequeue();

if (_directlyDerivingTypes.ContainsKey(potentialMatch))
{
foreach (var child in _directlyDerivingTypes[potentialMatch])
{
childTypesToCheck.Enqueue(child);
}
}
childTypesToCheck.Enqueue(child);
}
}

if (_classMappings.ContainsKey(potentialMatch))
if (_classMappings.ContainsKey(potentialMatch))
{
foreach (var mapping in _classMappings[potentialMatch])
{
if (mapping.IsMatch(classList))
{
foreach (var mapping in _classMappings[potentialMatch])
{
if (mapping.IsMatch(classList))
{
selectedTypes.Add(potentialMatch);
}
}
selectedTypes.Add(potentialMatch);
}
}
}

_cache[cacheKey] = cached = selectedTypes.GetMostDerivedTypes();
}

return cached;
return _cache[cacheKey] = selectedTypes.GetMostDerivedTypes();
}

/// <inheridoc/>
Expand Down
Expand Up @@ -19,7 +19,7 @@ public abstract class LoadingTestsBase : IntegrationTestsBase

internal interface ITrackedScopes
{
IList<Scope> TrackedScopes { get; }
IEnumerable<Scope> TrackedScopes { get; }
}

[Test]
Expand Down

0 comments on commit ab8f8e5

Please sign in to comment.