You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/08/31 09:10:26 UTC

[4/9] ignite git commit: IGNITE-5931 .NET: Fix type registration race condition

IGNITE-5931 .NET: Fix type registration race condition

This closes #2553


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/eae6e3b9
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/eae6e3b9
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/eae6e3b9

Branch: refs/heads/ignite-3478
Commit: eae6e3b9fd43b42fc9d74e61118800dc0f3f6f0c
Parents: d253c02
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Wed Aug 30 18:35:05 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Wed Aug 30 18:35:05 2017 +0300

----------------------------------------------------------------------
 .../Binary/BinaryDynamicRegistrationTest.cs     | 49 ++++++++++++++++++++
 .../Binary/BinarySelfTest.cs                    | 12 -----
 .../Cache/Affinity/AffinityFieldTest.cs         | 10 +++-
 .../Impl/Binary/Marshaller.cs                   | 43 ++++++++++-------
 4 files changed, 84 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/eae6e3b9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
index 4f458f4..01804b7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
@@ -25,6 +25,8 @@ namespace Apache.Ignite.Core.Tests.Binary
     using System.Collections.Generic;
     using System.IO;
     using System.Linq;
+    using System.Threading;
+    using System.Threading.Tasks;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Store;
@@ -357,6 +359,53 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
 
         /// <summary>
+        /// Tests registration in multiple threads.
+        /// </summary>
+        [Test]
+        public void TestRegistrationMultithreaded([Values(true, false)] bool useTypeName)
+        {
+            const int iterations = 50;
+            const int threads = 4;
+
+            using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var cache = ignite.CreateCache<int, int>("c").WithKeepBinary<int, IBinaryObject>();
+                var bin = ignite.GetBinary();
+                Func<Type, IBinaryObjectBuilder> getBuilder = x =>
+                    useTypeName ? bin.GetBuilder(x.FullName) : bin.GetBuilder(x);
+                    
+                var types = new[] { typeof(Foo), typeof(Bar), typeof(Bin) };
+
+                foreach (var type in types)
+                {
+                    var type0 = type;  // Modified closure.
+
+                    for (var i = 0; i < iterations; i++)
+                    {
+                        var countdown = new CountdownEvent(threads);
+
+                        Action registerType = () =>
+                        {
+                            countdown.Signal();
+                            Assert.IsTrue(countdown.Wait(5000));
+
+                            var binObj = getBuilder(type0).SetIntField("x", 1).Build();
+                            cache[1] = binObj;
+
+                            Assert.AreEqual(binObj, cache[1]);
+                        };
+
+                        var tasks = Enumerable.Range(0, threads)
+                            .Select(x => Task.Factory.StartNew(registerType))
+                            .ToArray();
+
+                        Task.WaitAll(tasks);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
         /// Tests the type registration.
         /// </summary>
         private static void Test(IIgnite ignite1, IIgnite ignite2)

http://git-wip-us.apache.org/repos/asf/ignite/blob/eae6e3b9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
index e24dca0..4237eda 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
@@ -1534,18 +1534,6 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual(nDateArr, obj2.NDateArr);
         }
 
-        [Test]
-        public void TestBinaryConfigurationValidation()
-        {
-            var cfg = new BinaryConfiguration(typeof (PropertyType))
-            {
-                Types = new[] {typeof(PropertyType).AssemblyQualifiedName}
-            };
-
-            // ReSharper disable once ObjectCreationAsStatement
-            Assert.Throws<BinaryObjectException>(() => new Marshaller(cfg));
-        }
-
         /// <summary>
         /// Tests the compact footer setting.
         /// </summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/eae6e3b9/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs
index 31326b7..c3482bb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs
@@ -76,7 +76,8 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
             _cache1.Put(new CacheKeyAttrOverride(), string.Empty);
 
             // Verify
-            foreach (var type in new[] { typeof(CacheKey) , typeof(CacheKeyAttr), typeof(CacheKeyAttrOverride)})
+            foreach (var type in new[] { typeof(CacheKey), typeof(CacheKeyAttr), 
+                typeof(CacheKeyAttrDynamicRegistration), typeof(CacheKeyAttrOverride)})
             {
                 Assert.AreEqual("AffinityKey", _cache1.Ignite.GetBinary().GetBinaryType(type).AffinityKeyFieldName);
                 Assert.AreEqual("AffinityKey", _cache2.Ignite.GetBinary().GetBinaryType(type).AffinityKeyFieldName);
@@ -91,6 +92,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
         {
             TestKeyLocation0((key, affKey) => new CacheKey {Key = key, AffinityKey = affKey});
             TestKeyLocation0((key, affKey) => new CacheKeyAttr {Key = key, AffinityKey = affKey});
+            TestKeyLocation0((key, affKey) => new CacheKeyAttrDynamicRegistration {Key = key, AffinityKey = affKey});
             TestKeyLocation0((key, affKey) => new CacheKeyAttrOverride {Key = key, AffinityKey = affKey});
         }
 
@@ -190,6 +192,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity
             [AffinityKeyMapped] public int AffinityKey { get; set; }
         }
 
+        private class CacheKeyAttrDynamicRegistration
+        {
+            public int Key { get; set; }
+            [AffinityKeyMapped] public int AffinityKey { get; set; }
+        }
+
         private class CacheKeyAttrOverride
         {
             [AffinityKeyMapped] public int Key { get; set; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/eae6e3b9/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index 5ede542..a6d5517 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -503,21 +503,28 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             desc = desc == null
                 ? new BinaryFullTypeDescriptor(type, typeId, typeName, true, _cfg.NameMapper,
-                    _cfg.IdMapper, ser, false, null, BinaryUtils.IsIgniteEnum(type), registered)
+                    _cfg.IdMapper, ser, false, GetAffinityKeyFieldNameFromAttribute(type), 
+                    BinaryUtils.IsIgniteEnum(type), registered)
                 : new BinaryFullTypeDescriptor(desc, type, ser, registered);
 
             if (RegistrationDisabled)
+            {
                 return desc;
+            }
 
             var typeKey = BinaryUtils.TypeKey(true, typeId);
 
             var desc0 = _idToDesc.GetOrAdd(typeKey, x => desc);
-            if (desc0.Type != null && desc0.Type.FullName != type.FullName)
+            if (desc0.Type != null && desc0.TypeName != typeName)
+            {
                 ThrowConflictingTypeError(type, desc0.Type, typeId);
+            }
 
             desc0 = _typeNameToDesc.GetOrAdd(typeName, x => desc);
-            if (desc0.Type != null && desc0.Type.FullName != type.FullName)
+            if (desc0.Type != null && desc0.TypeName != typeName)
+            {
                 ThrowConflictingTypeError(type, desc0.Type, typeId);
+            }
 
             _typeToDesc.Set(type, desc);
 
@@ -652,34 +659,36 @@ namespace Apache.Ignite.Core.Impl.Binary
             bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper,
             IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum)
         {
+            Debug.Assert(!string.IsNullOrEmpty(typeName));
+
             long typeKey = BinaryUtils.TypeKey(userType, typeId);
 
             BinaryFullTypeDescriptor conflictingType;
 
-            if (_idToDesc.TryGetValue(typeKey, out conflictingType))
+            if (_idToDesc.TryGetValue(typeKey, out conflictingType) && conflictingType.TypeName != typeName)
             {
-                var type1 = conflictingType.Type != null
-                    ? conflictingType.Type.AssemblyQualifiedName
-                    : conflictingType.TypeName;
-
-                var type2 = type != null ? type.AssemblyQualifiedName : typeName;
-
-                ThrowConflictingTypeError(type1, type2, typeId);
+                ThrowConflictingTypeError(typeName, conflictingType.TypeName, typeId);
             }
 
-            if (userType && _typeNameToDesc.ContainsKey(typeName))
-                throw new BinaryObjectException("Conflicting type name: " + typeName);
-
             var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, 
                 serializer, keepDeserialized, affKeyFieldName, isEnum);
 
+            if (RegistrationDisabled)
+            {
+                return descriptor;
+            }
+
             if (type != null)
-                _typeToDesc.GetOrAdd(type, x => descriptor);
+            {
+                _typeToDesc.Set(type, descriptor);
+            }
 
             if (userType)
-                _typeNameToDesc.GetOrAdd(typeName, x => descriptor);
+            {
+                _typeNameToDesc.Set(typeName, descriptor);
+            }
 
-            _idToDesc.GetOrAdd(typeKey, _ => descriptor);
+            _idToDesc.Set(typeKey, descriptor);
 
             return descriptor;
         }