Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 5429C200CE1 for ; Thu, 31 Aug 2017 11:10:26 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 52A9216ADF9; Thu, 31 Aug 2017 09:10:26 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 7B30416ADF2 for ; Thu, 31 Aug 2017 11:10:25 +0200 (CEST) Received: (qmail 23699 invoked by uid 500); 31 Aug 2017 09:10:24 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 23629 invoked by uid 99); 31 Aug 2017 09:10:24 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 Aug 2017 09:10:24 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id D0B1EF559F; Thu, 31 Aug 2017 09:10:23 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sboikov@apache.org To: commits@ignite.apache.org Date: Thu, 31 Aug 2017 09:10:26 -0000 Message-Id: <18d1c74f682d41cd8914be6e5eb3c8c3@git.apache.org> In-Reply-To: <048c66f2f1674ec0b50a112d95a5a13a@git.apache.org> References: <048c66f2f1674ec0b50a112d95a5a13a@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [4/9] ignite git commit: IGNITE-5931 .NET: Fix type registration race condition archived-at: Thu, 31 Aug 2017 09:10:26 -0000 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 Authored: Wed Aug 30 18:35:05 2017 +0300 Committer: Pavel Tupitsyn 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 } /// + /// Tests registration in multiple threads. + /// + [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("c").WithKeepBinary(); + var bin = ignite.GetBinary(); + Func 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); + } + } + } + } + + /// /// Tests the type registration. /// 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(() => new Marshaller(cfg)); - } - /// /// Tests the compact footer setting. /// 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; }