Skip to content

Commit

Permalink
Make convention thread-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Jul 1, 2019
1 parent a4ae303 commit f29ed14
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
Expand All @@ -21,13 +21,15 @@ public abstract class NonNullableConventionBase

private const string NullableAttributeFullName = "System.Runtime.CompilerServices.NullableAttribute";
private const string NullableContextAttributeFullName = "System.Runtime.CompilerServices.NullableContextAttribute";
private readonly object _nullableAttrLock = new object();
private readonly object _nullableContextAttrLock = new object();
private Type _nullableAttrType;
private Type _nullableContextAttrType;
private FieldInfo _nullableFlagsFieldInfo;
private FieldInfo _nullableContextFlagFieldInfo;

private readonly Dictionary<Type, bool> _typeNonNullabilityContextCache;
private readonly Dictionary<Module, bool> _moduleNonNullabilityContextCache;
private readonly ConcurrentDictionary<Type, bool> _typeNonNullabilityContextCache;
private readonly ConcurrentDictionary<Module, bool> _moduleNonNullabilityContextCache;

/// <summary>
/// Creates a new instance of <see cref="NonNullableConventionBase" />.
Expand All @@ -37,8 +39,8 @@ protected NonNullableConventionBase([NotNull] ProviderConventionSetBuilderDepend
{
Dependencies = dependencies;

_typeNonNullabilityContextCache = new Dictionary<Type, bool>();
_moduleNonNullabilityContextCache = new Dictionary<Module, bool>();
_typeNonNullabilityContextCache = new ConcurrentDictionary<Type, bool>();
_moduleNonNullabilityContextCache = new ConcurrentDictionary<Module, bool>();
}

/// <summary>
Expand All @@ -48,18 +50,22 @@ protected NonNullableConventionBase([NotNull] ProviderConventionSetBuilderDepend

private byte? GetNullabilityContextFlag(Attribute[] attributes)
{
if (attributes.FirstOrDefault(a => a.GetType().FullName == NullableContextAttributeFullName) is object attribute)
if (attributes.FirstOrDefault(a => a.GetType().FullName == NullableContextAttributeFullName) is Attribute attribute)
{
var attributeType = attribute.GetType();
if (attributeType != _nullableContextAttrType)
{
_nullableContextFlagFieldInfo = attributeType.GetField("Flag");
_nullableContextAttrType = attributeType;
}

if (_nullableContextFlagFieldInfo?.GetValue(attribute) is byte flag)
lock (_nullableContextAttrLock)
{
return flag;
if (attributeType != _nullableContextAttrType)
{
_nullableContextFlagFieldInfo = attributeType.GetField("Flag");
_nullableContextAttrType = attributeType;
}

if (_nullableContextFlagFieldInfo?.GetValue(attribute) is byte flag)
{
return flag;
}
}
}

Expand All @@ -80,19 +86,23 @@ protected virtual bool IsNonNullable([NotNull] MemberInfo memberInfo)

// First look for NullableAttribute on the member itself
if (Attribute.GetCustomAttributes(memberInfo, true)
.FirstOrDefault(a => a.GetType().FullName == NullableAttributeFullName) is { } attribute)
.FirstOrDefault(a => a.GetType().FullName == NullableAttributeFullName) is Attribute attribute)
{
var attributeType = attribute.GetType();
if (attributeType != _nullableAttrType)
{
_nullableFlagsFieldInfo = attributeType.GetField("NullableFlags");
_nullableAttrType = attributeType;
}

if (_nullableFlagsFieldInfo?.GetValue(attribute) is byte[] flags
&& flags.FirstOrDefault() == 1)
lock (_nullableAttrLock)
{
return true;
if (attributeType != _nullableAttrType)
{
_nullableFlagsFieldInfo = attributeType.GetField("NullableFlags");
_nullableAttrType = attributeType;
}

if (_nullableFlagsFieldInfo?.GetValue(attribute) is byte[] flags
&& flags.FirstOrDefault() == 1)
{
return true;
}
}
}

Expand Down

0 comments on commit f29ed14

Please sign in to comment.