Skip to content

Commit

Permalink
fixed: #116 and the race condition with open-generics
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Apr 29, 2019
1 parent fb43768 commit ae17163
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 26 deletions.
35 changes: 25 additions & 10 deletions src/DryIoc/Container.cs
Expand Up @@ -764,7 +764,7 @@ public IResolverContext WithCurrentScope(IScope scope)
registry.DropFactoryCache(oldFactory, serviceType);
else
((FactoriesEntry)oldEntry).Factories.Enumerate().ToArray()
.DoPer(x => registry.DropFactoryCache(x.Value, serviceType, serviceKey));
.ForEach(x => registry.DropFactoryCache(x.Value, serviceType, serviceKey));
}

return registry;
Expand Down Expand Up @@ -1266,11 +1266,22 @@ Expression IContainer.GetDecoratorExpressionOrDefault(Request request)
{
appliedDecoratorIDs = appliedDecoratorIDs ?? GetAppliedDecoratorIDs(request);
if (!appliedDecoratorIDs.IsNullOrEmpty())
{
genericDecorators = genericDecorators
.Match(appliedDecoratorIDs,
(ids, d) => d.FactoryGenerator == null
? ids.IndexOf(d.FactoryID) == -1
: d.FactoryGenerator.GeneratedFactories.Enumerate().All(f => ids.IndexOf(f.Value.FactoryID) == -1));
(appliedDecIds, d) =>
{
var factoryGenerator = d.FactoryGenerator;
if (factoryGenerator == null)
return appliedDecIds.IndexOf(d.FactoryID) == -1;

foreach (var entry in factoryGenerator.GeneratedFactories.Enumerate())
if (appliedDecIds.IndexOf(entry.Value.FactoryID) != -1)
return false;

return true;
});
}

// Generate closed-generic versions
if (!genericDecorators.IsNullOrEmpty())
Expand Down Expand Up @@ -1423,7 +1434,7 @@ public Expression GetConstantExpression(object item, Type itemType = null, bool
Error.StateIsRequiredToUseItem, item);

return itemType == null ? Constant(item) : Constant(item, itemType);
}
}l

private static readonly MethodInfo _kvOfMethod =
typeof(KV).GetTypeInfo().GetDeclaredMethod(nameof(KV.Of));
Expand Down Expand Up @@ -2130,7 +2141,7 @@ private Registry UnregisterServiceFactory(Type serviceType, object serviceKey =
else
(removed as Factory[] ??
((FactoriesEntry)removed).Factories.Enumerate().Select(f => f.Value).ToArray())
.DoPer(x => registry.DropFactoryCache(x, serviceType, serviceKey));
.ForEach(x => registry.DropFactoryCache(x, serviceType, serviceKey));

return registry;
}
Expand Down Expand Up @@ -8566,10 +8577,14 @@ public Factory GetGeneratedFactory(Request request, bool ifErrorReturnDefault =

var closedGenericFactory = new ReflectionFactory(implType, openFactory.Reuse, made, openFactory.Setup)
{
Caching = openFactory.Caching,
GeneratorFactoryID = openFactory.FactoryID
GeneratorFactoryID = openFactory.FactoryID,
Caching = openFactory.Caching
};
_generatedFactories.AddOrUpdate(generatedFactoryKey, closedGenericFactory);

// we should use whatever the first factory is registered because it can be used already in decorators and recursive factories check
_generatedFactories.Swap(generatedFactoryKey, closedGenericFactory,
(genFacKey, fac, facs) => facs.AddOrUpdate(genFacKey, fac, (oldFac, _) => closedGenericFactory = oldFac));

return closedGenericFactory;
}

Expand Down Expand Up @@ -10651,7 +10666,7 @@ internal static class RefMap
Ref.Swap(ref map, x => x.AddOrUpdate(key, value));

public static void AddOrUpdate<K, V>(this Ref<ImHashMap<K, V>> map, K key, V value) =>
map.Swap(key, value, (m, k, v) => m.AddOrUpdate(k, v));
map.Swap(key, value, (k, v, m) => m.AddOrUpdate(k, v));

public static void AddOrUpdate<K, V>(ref ImHashMap<K, V> map, K key, V value) =>
Ref.Swap(ref map, x => x.AddOrUpdate(key, value));
Expand Down
20 changes: 9 additions & 11 deletions src/DryIoc/ImTools.cs
Expand Up @@ -256,14 +256,12 @@ public static T SingleOrDefaultIfMany<T>(this IEnumerable<T> source)
if (!e.MoveNext())
return default(T);
var it = e.Current;
if (!e.MoveNext())
return it;
return default(T);
return !e.MoveNext() ? it : default(T);
}
}

/// <summary>Does <paramref name="action"/> for each item</summary>
public static void DoPer<T>(this T[] source, Action<T> action)
public static void ForEach<T>(this T[] source, Action<T> action)
{
if (!source.IsNullOrEmpty())
for (var i = 0; i < source.Length; i++)
Expand Down Expand Up @@ -635,10 +633,10 @@ public Ref(T initialValue = default(T))
public T Swap(Func<T, T> getNewValue) => Ref.Swap(ref _value, getNewValue);

/// Option without allocation for capturing `a` in closure of `getNewValue`
public T Swap<A>(A a, Func<T, A, T> getNewValue) => Ref.Swap(ref _value, a, getNewValue);
public T Swap<A>(A a, Func<A, T, T> getNewValue) => Ref.Swap(ref _value, a, getNewValue);

/// Option without allocation for capturing `a` and `b` in closure of `getNewValue`
public T Swap<A, B>(A a, B b, Func<T, A, B, T> getNewValue) => Ref.Swap(ref _value, a, b, getNewValue);
public T Swap<A, B>(A a, B b, Func<A, B, T, T> getNewValue) => Ref.Swap(ref _value, a, b, getNewValue);

/// <summary>Just sets new value ignoring any intermingled changes.</summary>
/// <param name="newValue"></param> <returns>old value</returns>
Expand Down Expand Up @@ -695,13 +693,13 @@ public static class Ref
}

/// Option without allocation for capturing `a` in closure of `getNewValue`
public static T Swap<T, A>(ref T value, A a, Func<T, A, T> getNewValue) where T : class
public static T Swap<A, T>(ref T value, A a, Func<A, T, T> getNewValue) where T : class
{
var retryCount = 0;
while (true)
{
var oldValue = value;
var newValue = getNewValue(oldValue, a);
var newValue = getNewValue(a, oldValue);
if (Interlocked.CompareExchange(ref value, newValue, oldValue) == oldValue)
return oldValue;
if (++retryCount > RETRY_COUNT_UNTIL_THROW)
Expand All @@ -710,13 +708,13 @@ public static class Ref
}

/// Option without allocation for capturing `a` and `b` in closure of `getNewValue`
public static T Swap<T, A, B>(ref T value, A a, B b, Func<T, A, B, T> getNewValue) where T : class
public static T Swap<A, B, T>(ref T value, A a, B b, Func<A, B, T, T> getNewValue) where T : class
{
var retryCount = 0;
while (true)
{
var oldValue = value;
var newValue = getNewValue(oldValue, a, b);
var newValue = getNewValue(a, b, oldValue);
if (Interlocked.CompareExchange(ref value, newValue, oldValue) == oldValue)
return oldValue;
if (++retryCount > RETRY_COUNT_UNTIL_THROW)
Expand All @@ -731,7 +729,7 @@ public static class Ref
" times But there is always someone else intervened.";
}

/// <summary>Printable thingy via provided printer </summary>
/// <summary>Printable string via provided printer </summary>
public interface IPrintable
{
/// <summary>Print to the provided string builder via the provided printer.</summary>
Expand Down
Expand Up @@ -8,7 +8,7 @@ namespace DryIoc.IssuesTests
[TestFixture]
public class GHIssue116_DryIoc_Resolve_with_decorators_goes_wrong_for_parallel_execution
{
[Test][Ignore("fixme")]
[Test]
public async Task DryIoc_Resolve_parallel_execution()
{
var container = new Container();
Expand Down
Expand Up @@ -117,9 +117,6 @@ public static void Log(string s)
Debug.WriteLine(s);
}

public static string String()
{
return string.Join("\r\n", Lines);
}
public static string String() => string.Join("\r\n", Lines);
}
}

0 comments on commit ae17163

Please sign in to comment.