IGNITE-14293 .NET: Fix AffinityKey metadata in QueryEntity.KeyType
`AffinityKey` system type, when used as a `QueryEntiry` key, got overwritten by `UnmanagedCallbacks.BinaryTypeGet` call, which broke the mapping to a corresponding Java type.
* Add missing check for existing registered type (actual fix in Marshaller.cs)
* Add check for system type overwrite
* Add test for `AffinityKey` + `QueryEntity`
Co-authored-by: Igor Sapego <isapego@apache.org>
(cherry picked from commit 8cc19b1041b64d7dd3bb368ce4b9cadee07a3718)
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
index 37bc53b..cd7a327 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityTest.cs
@@ -122,6 +122,46 @@
}
/// <summary>
+ /// Tests that <see cref="AffinityKey"/> works when used as <see cref="QueryEntity.KeyType"/>.
+ /// </summary>
+ [Test]
+ public void TestAffinityKeyWithQueryEntity()
+ {
+ var cacheCfg = new CacheConfiguration(TestUtils.TestName)
+ {
+ QueryEntities = new List<QueryEntity>
+ {
+ new QueryEntity(typeof(AffinityKey), typeof(QueryEntityValue))
+ }
+ };
+
+ var ignite = Ignition.GetIgnite("grid-0");
+ var cache = ignite.GetOrCreateCache<AffinityKey, QueryEntityValue>(cacheCfg);
+ var aff = ignite.GetAffinity(cache.Name);
+
+ var ignite2 = Ignition.GetIgnite("grid-1");
+ var cache2 = ignite2.GetOrCreateCache<AffinityKey, QueryEntityValue>(cacheCfg);
+ var aff2 = ignite2.GetAffinity(cache2.Name);
+
+ // Check mapping.
+ for (var i = 0; i < 100; i++)
+ {
+ Assert.AreEqual(aff.GetPartition(i), aff.GetPartition(new AffinityKey("foo" + i, i)));
+ Assert.AreEqual(aff2.GetPartition(i), aff2.GetPartition(new AffinityKey("bar" + i, i)));
+ Assert.AreEqual(aff.GetPartition(i), aff2.GetPartition(i));
+ }
+
+ // Check put/get.
+ var key = new AffinityKey("x", 123);
+ var expected = new QueryEntityValue {Name = "y", AffKey = 321};
+ cache[key] = expected;
+
+ var val = cache2[key];
+ Assert.AreEqual(expected.Name, val.Name);
+ Assert.AreEqual(expected.AffKey, val.AffKey);
+ }
+
+ /// <summary>
/// Tests that <see cref="AffinityKeyMappedAttribute"/> works when used on a property of a type that is
/// specified as <see cref="QueryEntity.KeyType"/> or <see cref="QueryEntity.ValueType"/>.
/// </summary>
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 f6346a5..a7c5411 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
@@ -565,6 +566,11 @@
if (type != null)
{
+ if (_typeToDesc.TryGetValue(type, out desc))
+ {
+ return desc;
+ }
+
return AddUserType(type, typeId, GetTypeName(type), true, desc);
}
}
@@ -665,12 +671,26 @@
ThrowConflictingTypeError(type, desc0.Type, typeId);
}
+ ValidateRegistration(type);
_typeToDesc.Set(type, desc);
return desc;
}
/// <summary>
+ /// Validates type registration.
+ /// </summary>
+ [ExcludeFromCodeCoverage]
+ private void ValidateRegistration(Type type)
+ {
+ BinaryFullTypeDescriptor desc;
+ if (_typeToDesc.TryGetValue(type, out desc) && !desc.UserType)
+ {
+ throw new BinaryObjectException("Invalid attempt to overwrite system type registration: " + type);
+ }
+ }
+
+ /// <summary>
/// Throws the conflicting type error.
/// </summary>
private static void ThrowConflictingTypeError(object type1, object type2, int typeId)
@@ -805,6 +825,7 @@
if (type != null)
{
+ ValidateRegistration(type);
_typeToDesc.Set(type, descriptor);
}