From: <fab...@us...> - 2008-08-16 07:02:38
|
Revision: 3710 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3710&view=rev Author: fabiomaulo Date: 2008-08-16 07:02:48 +0000 (Sat, 16 Aug 2008) Log Message: ----------- - Fix NH-1251 - TypeFactory thread safe + refactoring NET2.0 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs Modified: trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-08-16 06:10:38 UTC (rev 3709) +++ trunk/nhibernate/src/NHibernate/Type/TypeFactory.cs 2008-08-16 07:02:48 UTC (rev 3710) @@ -10,6 +10,7 @@ using NHibernate.Tuple; using NHibernate.UserTypes; using NHibernate.Util; +using System.Runtime.CompilerServices; namespace NHibernate.Type { @@ -32,8 +33,8 @@ PrecisionScale } - private static char[] precisionScaleSplit = new char[] {'(', ')', ','}; - private static char[] lengthSplit = new char[] {'(', ')'}; + private static readonly char[] precisionScaleSplit = new char[] {'(', ')', ','}; + private static readonly char[] lengthSplit = new char[] {'(', ')'}; /* * Maps the string representation of the type to the IType. The string @@ -54,11 +55,16 @@ * "String(l)" -> instance of StringType with specified l * "System.String(l)" -> instance of StringType with specified l */ - private static Hashtable typeByTypeOfName = Hashtable.Synchronized(new Hashtable(79)); - private static Hashtable getTypeDelegatesWithLength = Hashtable.Synchronized(new Hashtable(7)); - private static Hashtable getTypeDelegatesWithPrecision = Hashtable.Synchronized(new Hashtable(3)); + private static readonly IDictionary<string, IType> typeByTypeOfName = + new ThreadSafeDictionary<string, IType>(new Dictionary<string, IType>()); + private static readonly IDictionary<string, GetNullableTypeWithLength> getTypeDelegatesWithLength = + new ThreadSafeDictionary<string, GetNullableTypeWithLength>(new Dictionary<string, GetNullableTypeWithLength>()); + + private static readonly IDictionary<string, GetNullableTypeWithPrecision> getTypeDelegatesWithPrecision = + new ThreadSafeDictionary<string, GetNullableTypeWithPrecision>(new Dictionary<string, GetNullableTypeWithPrecision>()); + private delegate NullableType GetNullableTypeWithLength(int length); private delegate NullableType GetNullableTypeWithPrecision(byte precision, byte scale); @@ -121,7 +127,7 @@ // add the mappings of the NHibernate specific names that are used in type="" typeByTypeOfName[NHibernateUtil.AnsiString.Name] = NHibernateUtil.AnsiString; - getTypeDelegatesWithLength.Add(NHibernateUtil.AnsiString.Name, new GetNullableTypeWithLength(GetAnsiStringType)); + getTypeDelegatesWithLength.Add(NHibernateUtil.AnsiString.Name, GetAnsiStringType); typeByTypeOfName[NHibernateUtil.AnsiChar.Name] = NHibernateUtil.AnsiChar; typeByTypeOfName[NHibernateUtil.BinaryBlob.Name] = NHibernateUtil.BinaryBlob; @@ -155,12 +161,12 @@ typeByTypeOfName["yes_no"] = NHibernateUtil.YesNo; - getTypeDelegatesWithLength.Add(NHibernateUtil.Binary.Name, new GetNullableTypeWithLength(GetBinaryType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.Serializable.Name, new GetNullableTypeWithLength(GetSerializableType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.String.Name, new GetNullableTypeWithLength(GetStringType)); - getTypeDelegatesWithLength.Add(NHibernateUtil.Class.Name, new GetNullableTypeWithLength(GetTypeType)); + getTypeDelegatesWithLength.Add(NHibernateUtil.Binary.Name, GetBinaryType); + getTypeDelegatesWithLength.Add(NHibernateUtil.Serializable.Name, GetSerializableType); + getTypeDelegatesWithLength.Add(NHibernateUtil.String.Name, GetStringType); + getTypeDelegatesWithLength.Add(NHibernateUtil.Class.Name, GetTypeType); - getTypeDelegatesWithPrecision.Add(NHibernateUtil.Decimal.Name, new GetNullableTypeWithPrecision(GetDecimalType)); + getTypeDelegatesWithPrecision.Add(NHibernateUtil.Decimal.Name, GetDecimalType); } @@ -230,13 +236,12 @@ /// </remarks> public static IType Basic(string name) { - string typeName = String.Empty; + string typeName; // Use the basic name (such as String or String(255)) to get the // instance of the IType object. IType returnType; - returnType = (IType) typeByTypeOfName[name]; - if (returnType != null) + if (typeByTypeOfName.TryGetValue(name,out returnType)) { return returnType; } @@ -249,9 +254,6 @@ if (typeClassification == TypeClassification.PrecisionScale) { //precision/scale based - GetNullableTypeWithPrecision precisionDelegate; - byte precision; - byte scale; string[] parsedName = name.Split(precisionScaleSplit); if (parsedName.Length < 4) @@ -261,22 +263,20 @@ } typeName = parsedName[0].Trim(); - precision = Byte.Parse(parsedName[1].Trim()); - scale = Byte.Parse(parsedName[2].Trim()); + byte precision = Byte.Parse(parsedName[1].Trim()); + byte scale = Byte.Parse(parsedName[2].Trim()); - if (getTypeDelegatesWithPrecision.ContainsKey(typeName) == false) + GetNullableTypeWithPrecision precisionDelegate; + if (!getTypeDelegatesWithPrecision.TryGetValue(typeName, out precisionDelegate)) { return null; } - precisionDelegate = (GetNullableTypeWithPrecision) getTypeDelegatesWithPrecision[typeName]; return precisionDelegate(precision, scale); } else if (typeClassification == TypeClassification.Length) { //length based - GetNullableTypeWithLength lengthDelegate; - int length; string[] parsedName = name.Split(lengthSplit); if (parsedName.Length < 3) @@ -285,15 +285,15 @@ } typeName = parsedName[0].Trim(); - length = Int32.Parse(parsedName[1].Trim()); + int length = Int32.Parse(parsedName[1].Trim()); - if (getTypeDelegatesWithLength.ContainsKey(typeName) == false) - // we were not able to find a delegate to get the Type + GetNullableTypeWithLength lengthDelegate; + + if (!getTypeDelegatesWithLength.TryGetValue(typeName, out lengthDelegate)) { + // we were not able to find a delegate to get the Type return null; } - - lengthDelegate = (GetNullableTypeWithLength) getTypeDelegatesWithLength[typeName]; return lengthDelegate(length); } @@ -307,23 +307,20 @@ } } - private static IType AddToTypeOfName(string key, IType type) + private static void AddToTypeOfName(string key, IType type) { typeByTypeOfName.Add(key, type); typeByTypeOfName.Add(type.Name, type); - return type; } - private static IType AddToTypeOfNameWithLength(string key, IType type) + private static void AddToTypeOfNameWithLength(string key, IType type) { typeByTypeOfName.Add(key, type); - return type; } - private static IType AddToTypeOfNameWithPrecision(string key, IType type) + private static void AddToTypeOfNameWithPrecision(string key, IType type) { typeByTypeOfName.Add(key, type); - return type; } private static string GetKeyForLengthBased(string name, int length) @@ -375,14 +372,8 @@ { parsedTypeName = typeName.Split(lengthSplit); } - else if (typeClassification == TypeClassification.PrecisionScale) - { - parsedTypeName = typeName.Split(precisionScaleSplit); - } - else - { - parsedTypeName = new string[] {typeName}; - } + else + parsedTypeName = typeClassification == TypeClassification.PrecisionScale ? typeName.Split(precisionScaleSplit) : new string[] {typeName}; System.Type typeClass; @@ -455,22 +446,19 @@ return genericClass.IsSubclassOf(typeof (Enum)); } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetAnsiStringType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.AnsiString.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new AnsiStringType(SqlTypeFactory.GetAnsiString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } /// <summary> @@ -483,6 +471,7 @@ /// been added to the basicNameMap with the keys <c>Byte[](length)</c> and /// <c>NHibernate.Type.BinaryType(length)</c>. /// </remarks> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetBinaryType(int length) { //HACK: don't understand why SerializableType calls this with length=0 @@ -492,27 +481,28 @@ } string key = GetKeyForLengthBased(NHibernateUtil.Binary.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new BinaryType(SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetDecimalType(byte precision, byte scale) { string key = GetKeyForPrecisionScaleBased(NHibernateUtil.Decimal.Name, precision, scale); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new DecimalType(SqlTypeFactory.GetDecimal(precision, scale)); AddToTypeOfNameWithPrecision(key, returnType); } - return returnType; + return (NullableType)returnType; } /// <summary> @@ -534,95 +524,79 @@ /// with the default length, those keys will also be added. /// </para> /// </remarks> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(System.Type serializableType) { string key = serializableType.AssemblyQualifiedName; - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(serializableType); AddToTypeOfName(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="serializableType"></param> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(System.Type serializableType, int length) { string key = GetKeyForLengthBased(serializableType.AssemblyQualifiedName, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(serializableType, SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetSerializableType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.Serializable.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new SerializableType(typeof(object), SqlTypeFactory.GetBinary(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetStringType(int length) { string key = GetKeyForLengthBased(NHibernateUtil.String.Name, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new StringType(SqlTypeFactory.GetString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } - /// <summary> - /// - /// </summary> - /// <param name="length"></param> - /// <returns></returns> + [MethodImpl(MethodImplOptions.Synchronized)] public static NullableType GetTypeType(int length) { string key = GetKeyForLengthBased(typeof(TypeType).FullName, length); - NullableType returnType = (NullableType) typeByTypeOfName[key]; - if (returnType == null) + IType returnType; + if (!typeByTypeOfName.TryGetValue(key, out returnType)) { returnType = new TypeType(SqlTypeFactory.GetString(length)); AddToTypeOfNameWithLength(key, returnType); } - return returnType; + return (NullableType)returnType; } // Association Types Modified: trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs 2008-08-16 06:10:38 UTC (rev 3709) +++ trunk/nhibernate/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs 2008-08-16 07:02:48 UTC (rev 3710) @@ -1,5 +1,4 @@ using System; -using System.Threading; using log4net; using log4net.Repository.Hierarchy; using NHibernate.Type; @@ -79,6 +78,8 @@ [Test, Explicit] public void MultiThreadAccess() { + // Test added for NH-1251 + // If one thread break the test you can see the result in the console. ((Logger) log.Logger).Level = log4net.Core.Level.Debug; MultiThreadRunner<object>.ExecuteAction[] actions = new MultiThreadRunner<object>.ExecuteAction[] { @@ -108,7 +109,6 @@ mtr.TimeoutBetweenThreadStart = 2; mtr.Run(null); log.DebugFormat("{0} calls", totalCall); - TypeFactory.GetTypeType(rnd.Next()); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |