From a8454b38e4d6b3a5e0fffe96642f8e6d5096c10d Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Mon, 27 Jan 2020 21:05:24 -0800 Subject: [PATCH 1/2] NameBuilder concurrency issue fix --- Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs b/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs index 3dc68c71ee..fb1cacc004 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs @@ -5,6 +5,7 @@ // Created: 2007.08.27 using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -19,6 +20,7 @@ using Xtensive.Orm.Weaving; using Xtensive.Reflection; using FieldInfo = Xtensive.Orm.Model.FieldInfo; +using Module = System.Reflection.Module; using TypeInfo = Xtensive.Orm.Model.TypeInfo; namespace Xtensive.Orm.Providers @@ -36,8 +38,11 @@ public sealed class NameBuilder private const string ReferenceForeignKeyFormat = "FK_{0}_{1}_{2}"; private const string HierarchyForeignKeyFormat = "FK_{0}_{1}"; - private readonly Dictionary, string> fieldNameCache = new Dictionary, string>(); - private readonly object _lock = new object(); + private readonly ConcurrentDictionary fieldNameCache = + new ConcurrentDictionary(); + private static readonly Func _fieldNameCacheValueFactory = + field => field.GetAttribute()?.Name ?? field.Name; + private readonly int maxIdentifierLength; private readonly NamingConvention namingConvention; private readonly bool isMultidatabase; @@ -182,38 +187,14 @@ public string BuildFieldName(FieldDef field) } private string BuildFieldNameInternal(PropertyInfo propertyInfo) - { - var key = new Pair(propertyInfo.ReflectedType, propertyInfo.Name); - - lock (fieldNameCache) { - string result; - if (fieldNameCache.TryGetValue(key, out result)) - return result; - var attribute = propertyInfo.GetAttribute(); - if (attribute!=null) { - result = attribute.Name; - fieldNameCache.Add(key, result); - return result; - } - } - - return propertyInfo.Name; - } + => fieldNameCache.GetOrAdd(propertyInfo, _fieldNameCacheValueFactory); /// /// Builds the name of the field. /// /// The property info. public string BuildFieldName(PropertyInfo propertyInfo) - { - lock (fieldNameCache) { - var key = new Pair(propertyInfo.ReflectedType, propertyInfo.Name); - string result; - return fieldNameCache.TryGetValue(key, out result) - ? result - : propertyInfo.Name; - } - } + => fieldNameCache.TryGetValue(propertyInfo, out string result) ? result : propertyInfo.Name; /// /// Builds the name of the explicitly implemented field. From 8ef08cb0cd7aca1869395edfad35a60863af6080 Mon Sep 17 00:00:00 2001 From: AlexUstinov Date: Fri, 7 Feb 2020 00:00:59 -0800 Subject: [PATCH 2/2] Fixes after code review #1 --- Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs b/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs index feffdf77cc..b74e73d6e9 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/NameBuilder.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using Xtensive.Core; @@ -20,7 +21,6 @@ using Xtensive.Orm.Weaving; using Xtensive.Reflection; using FieldInfo = Xtensive.Orm.Model.FieldInfo; -using Module = System.Reflection.Module; using TypeInfo = Xtensive.Orm.Model.TypeInfo; namespace Xtensive.Orm.Providers @@ -38,15 +38,15 @@ public sealed class NameBuilder private const string ReferenceForeignKeyFormat = "FK_{0}_{1}_{2}"; private const string HierarchyForeignKeyFormat = "FK_{0}_{1}"; - private readonly ConcurrentDictionary fieldNameCache = - new ConcurrentDictionary(); - private static readonly Func _fieldNameCacheValueFactory = + private static readonly Func fieldNameCacheValueFactory = field => field.GetAttribute()?.Name ?? field.Name; private readonly int maxIdentifierLength; private readonly NamingConvention namingConvention; private readonly bool isMultidatabase; private readonly string defaultDatabase; + private readonly ConcurrentDictionary fieldNameCache = + new ConcurrentDictionary(); /// /// Gets the column name. @@ -186,8 +186,9 @@ public string BuildFieldName(FieldDef field) return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private string BuildFieldNameInternal(PropertyInfo propertyInfo) - => fieldNameCache.GetOrAdd(propertyInfo, _fieldNameCacheValueFactory); + => fieldNameCache.GetOrAdd(propertyInfo, fieldNameCacheValueFactory); /// /// Builds the name of the field. @@ -195,7 +196,7 @@ private string BuildFieldNameInternal(PropertyInfo propertyInfo) /// The property info. public string BuildFieldName(PropertyInfo propertyInfo) { - ArgumentValidator.EnsureArgumentNotNull(propertyInfo, nameof(propertyInfo)); + ArgumentValidator.EnsureArgumentNotNull(propertyInfo, "propertyInfo"); return BuildFieldNameInternal(propertyInfo); }