This is an automated email from the ASF dual-hosted git repository.

ptupitsyn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new bdfc379fe92 IGNITE-19359 .NET: Fix 'Affinity keys are not supported' 
exception (#10727)
bdfc379fe92 is described below

commit bdfc379fe925782d7ff581985389b8268a39a3d5
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Thu May 18 12:45:49 2023 +0300

    IGNITE-19359 .NET: Fix 'Affinity keys are not supported' exception (#10727)
    
    1. Support hash calculation for affinity keys.
    2. When partition awareness hash still can't be computed, do not throw an 
exception; log a warning (once per type) and use the default connection.
---
 .../Client/Cache/PartitionAwarenessTest.cs         | 114 +++++++++++++++++++--
 .../Client/Cache/TestKeyWithAffinityBinarizable.cs |  75 ++++++++++++++
 .../Client/Cache/TestKeyWithUserObjectAffinity.cs  |  56 ++++++++++
 .../Impl/Binary/BinaryHashCodeUtils.cs             |  72 +++++++++----
 .../Impl/Binary/BinaryObjectSchemaHolder.cs        |  20 ++--
 .../Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs |   7 +-
 .../Impl/Client/ClientFailoverSocket.cs            |  40 ++++++--
 7 files changed, 333 insertions(+), 51 deletions(-)

diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
index 2ae51699bae..7757f826a61 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/PartitionAwarenessTest.cs
@@ -28,7 +28,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
     using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Client.Cache;
     using Apache.Ignite.Core.Client.DataStructures;
-    using Apache.Ignite.Core.Common;
     using NUnit.Framework;
 
     /// <summary>
@@ -127,11 +126,17 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
         }
 
         [Test]
-        public void 
CachePut_UserDefinedTypeWithAffinityKey_ThrowsIgniteException()
+        [TestCase(1, 1)]
+        [TestCase(2, 0)]
+        [TestCase(3, 0)]
+        [TestCase(4, 1)]
+        [TestCase(5, 1)]
+        [TestCase(6, 2)]
+        public void 
CachePut_UserDefinedTypeWithAffinityKey_RequestIsRoutedToPrimaryNode(int key, 
int gridIdx)
         {
             // Note: annotation-based configuration is not supported on Java 
side.
             // Use manual configuration instead.
-            var cacheClientConfiguration = new 
CacheClientConfiguration("c_custom_key_aff")
+            var cacheClientConfiguration = new 
CacheClientConfiguration(TestUtils.TestName)
             {
                 KeyConfiguration = new List<CacheKeyConfiguration>
                 {
@@ -141,14 +146,109 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
                     }
                 }
             };
+
             var cache = Client.GetOrCreateCache<TestKeyWithAffinity, 
int>(cacheClientConfiguration);
 
-            var ex = Assert.Throws<IgniteException>(() => cache.Put(new 
TestKeyWithAffinity(1, "1"), 1));
+            cache.Put(new TestKeyWithAffinity(key, Guid.NewGuid().ToString()), 
key);
+            Assert.AreEqual(gridIdx, GetClientRequestGridIndex("Put"));
+        }
+
+        [Test]
+        [TestCase(1, 1)]
+        [TestCase(2, 0)]
+        [TestCase(3, 0)]
+        [TestCase(4, 1)]
+        [TestCase(5, 1)]
+        [TestCase(6, 2)]
+        public void 
CachePut_UserDefinedTypeWithAffinityKeyBinarizable_RequestIsRoutedToPrimaryNode(int
 key, int gridIdx)
+        {
+            var cacheClientConfiguration = new 
CacheClientConfiguration(TestUtils.TestName)
+            {
+                KeyConfiguration = new List<CacheKeyConfiguration>
+                {
+                    new 
CacheKeyConfiguration(typeof(TestKeyWithAffinityBinarizable))
+                    {
+                        AffinityKeyFieldName = "id"
+                    }
+                }
+            };
+
+            var cache = 
Client.GetOrCreateCache<TestKeyWithAffinityBinarizable, 
int>(cacheClientConfiguration);
+
+            cache.Put(new TestKeyWithAffinityBinarizable(key, 
Guid.NewGuid().ToString()), key);
+            Assert.AreEqual(gridIdx, GetClientRequestGridIndex("Put"));
+        }
+
+        [Test]
+        public void 
CachePut_UserDefinedTypeWithAffinityKeyBinarizable_SkipKey_LogsWarningAndBypassesPartitionAwareness()
+        {
+            var cacheClientConfiguration = new 
CacheClientConfiguration(TestUtils.TestName)
+            {
+                KeyConfiguration = new List<CacheKeyConfiguration>
+                {
+                    new 
CacheKeyConfiguration(typeof(TestKeyWithAffinityBinarizable))
+                    {
+                        AffinityKeyFieldName = "id"
+                    }
+                }
+            };
+
+            var cache = 
Client.GetOrCreateCache<TestKeyWithAffinityBinarizable, 
int>(cacheClientConfiguration);
+
+            var logger = (ListLogger)Client.GetConfiguration().Logger;
+            logger.Clear();
+
+            cache.Put(new TestKeyWithAffinityBinarizable(123, 
Guid.NewGuid().ToString(), skipKey: true), 123);
+
+            Assert.AreEqual(
+                "Failed to compute partition awareness hash code for type " +
+                
"'Apache.Ignite.Core.Tests.Client.Cache.TestKeyWithAffinityBinarizable'",
+                logger.Entries.Single().Message);
+        }
+
+        [Test]
+        [TestCase(1, 0)]
+        [TestCase(2, 0)]
+        [TestCase(3, 0)]
+        [TestCase(4, 2)]
+        [TestCase(5, 2)]
+        [TestCase(6, 1)]
+        public void 
CachePut_UserDefinedTypeWithUserTypeAffinityKey_RequestIsRoutedToPrimaryNode(int
 key, int gridIdx)
+        {
+            var cacheClientConfiguration = new 
CacheClientConfiguration(TestUtils.TestName)
+            {
+                KeyConfiguration = new List<CacheKeyConfiguration>
+                {
+                    new 
CacheKeyConfiguration(typeof(TestKeyWithUserObjectAffinity))
+                    {
+                        AffinityKeyFieldName = "_key"
+                    }
+                }
+            };
+
+            var cache = Client.GetOrCreateCache<TestKeyWithUserObjectAffinity, 
int>(cacheClientConfiguration);
+
+            var keyObj = new TestKeyWithUserObjectAffinity(new TestKey(key, 
key.ToString()), Guid.NewGuid().ToString());
+            cache.Put(keyObj, key);
+
+            Assert.AreEqual(gridIdx, GetClientRequestGridIndex("Put"));
+        }
+
+        [Test]
+        public void 
CachePut_MultidimensionalArrayKey_LogsWarningAndBypassesPartitionAwareness()
+        {
+            var logger = (ListLogger)Client.GetConfiguration().Logger;
+            logger.Clear();
+
+            var cache = Client.GetOrCreateCache<int[,], 
int>(TestUtils.TestName);
 
-            var expected = string.Format("Affinity keys are not supported. 
Object '{0}' has an affinity key.",
-                typeof(TestKeyWithAffinity));
+            // Two operations, single warning.
+            cache.Put(new int[1, 1], 1);
+            cache.Put(new int[2, 2], 2);
 
-            Assert.AreEqual(expected, ex.Message);
+            Assert.AreEqual(
+                "Failed to compute partition awareness hash code for type 
'System.Int32[,]'",
+                logger.Entries.Single().Message);
         }
 
         [Test]
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithAffinityBinarizable.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithAffinityBinarizable.cs
new file mode 100644
index 00000000000..dbe7a70f655
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithAffinityBinarizable.cs
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cache
+{
+    using Apache.Ignite.Core.Binary;
+
+    public sealed class TestKeyWithAffinityBinarizable : IBinarizable
+    {
+        private int _i;
+
+        private string _s;
+
+        private readonly bool _skipKey;
+
+        public TestKeyWithAffinityBinarizable(int i, string s, bool skipKey = 
false)
+        {
+            _i = i;
+            _s = s;
+            _skipKey = skipKey;
+        }
+
+        private bool Equals(TestKeyWithAffinityBinarizable other)
+        {
+            return _i == other._i && string.Equals(_s, other._s);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return Equals((TestKeyWithAffinityBinarizable) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                // ReSharper disable NonReadonlyMemberInGetHashCode 
(effectively readonly).
+                return (_i * 397) ^ (_s != null ? _s.GetHashCode() : 0);
+            }
+        }
+
+        public void WriteBinary(IBinaryWriter writer)
+        {
+            writer.WriteString("str", _s);
+
+            if (!_skipKey)
+            {
+                writer.WriteInt("id", _i);
+            }
+        }
+
+        public void ReadBinary(IBinaryReader reader)
+        {
+            _s = reader.ReadString("str");
+            _i = reader.ReadInt("id");
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithUserObjectAffinity.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithUserObjectAffinity.cs
new file mode 100644
index 00000000000..ee9d49c304c
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/TestKeyWithUserObjectAffinity.cs
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cache
+{
+    using Apache.Ignite.Core.Cache.Affinity;
+
+    public sealed class TestKeyWithUserObjectAffinity
+    {
+        [AffinityKeyMapped]
+        private readonly TestKey _key;
+
+        private readonly string _s;
+
+        public TestKeyWithUserObjectAffinity(TestKey key, string s)
+        {
+            _key = key;
+            _s = s;
+        }
+
+        private bool Equals(TestKeyWithUserObjectAffinity other)
+        {
+            return _key.Equals(other._key) && string.Equals(_s, other._s);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+            return Equals((TestKeyWithUserObjectAffinity) obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return (_key.GetHashCode() * 397) ^ (_s != null ? 
_s.GetHashCode() : 0);
+            }
+        }
+    }
+}
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHashCodeUtils.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHashCodeUtils.cs
index 213e90dd6e8..93a522a36fb 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHashCodeUtils.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryHashCodeUtils.cs
@@ -20,7 +20,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System;
     using System.Collections.Generic;
     using System.Diagnostics;
-    using Apache.Ignite.Core.Common;
+    using System.IO;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Common;
 
@@ -32,7 +32,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Gets the Ignite-specific hash code for the provided value.
         /// </summary>
-        public static unsafe int GetHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affinityKeyFieldIds)
+        public static unsafe int? GetHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affinityKeyFieldIds)
         {
             Debug.Assert(marsh != null);
             Debug.Assert(val != null);
@@ -125,7 +125,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Gets the Ignite-specific hash code for an array.
         /// </summary>
-        private static int GetArrayHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affinityKeyFieldIds)
+        private static int? GetArrayHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affinityKeyFieldIds)
         {
             var res = 1;
 
@@ -197,36 +197,52 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             if (arr.Rank != 1)
             {
-                throw new IgniteException(
-                    string.Format("Failed to compute hash code for object 
'{0}' of type '{1}': " +
-                                  "multidimensional arrays are not supported", 
val, val.GetType()));
+                return null;
             }
 
             foreach (var element in arr)
             {
-                res = 31 * res + (element == null ? 0 : GetHashCode(element, 
marsh, affinityKeyFieldIds));
+                res = 31 * res;
+
+                if (element != null)
+                {
+                    var elementHash = GetHashCode(element, marsh, 
affinityKeyFieldIds);
+
+                    if (elementHash == null)
+                    {
+                        return null;
+                    }
+
+                    res += elementHash.Value;
+                }
             }
 
             return res;
         }
 
-        // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
-        private static int GetComplexTypeHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affinityKeyFieldIds)
+        private static int? GetComplexTypeHashCode<T>(T val, Marshaller marsh, 
IDictionary<int, int> affKeyFieldIds)
         {
             using (var stream = new BinaryHeapStream(128))
             {
                 var writer = marsh.StartMarshal(stream);
 
                 int? hashCode = null;
+                int? affKeyOffset = null;
+                var multipleAffKeys = false;
 
-                writer.OnObjectWritten += (header, obj) =>
+                writer.OnObjectWritten += (header, schema, schemaIdx) =>
                 {
-                    if (affinityKeyFieldIds != null && 
affinityKeyFieldIds.ContainsKey(header.TypeId))
+                    if (affKeyFieldIds != null &&
+                        affKeyFieldIds.TryGetValue(header.TypeId, out var 
affKeyFieldId))
                     {
-                        var err = string.Format(
-                            "Affinity keys are not supported. Object '{0}' has 
an affinity key.", obj);
-
-                        throw new IgniteException(err);
+                        if (affKeyOffset != null)
+                        {
+                            multipleAffKeys = true;
+                            return;
+                        }
+
+                        affKeyOffset = schema.GetFieldOffset(schemaIdx, 
affKeyFieldId);
+                        return;
                     }
 
                     // In case of composite objects we need the last hash code.
@@ -234,15 +250,31 @@ namespace Apache.Ignite.Core.Impl.Binary
                 };
 
                 writer.Write(val);
+                marsh.FinishMarshal(writer);
 
-                if (hashCode != null)
+                if (multipleAffKeys)
                 {
-                    // ReSharper disable once 
PossibleInvalidOperationException (false detection).
-                    return hashCode.Value;
+                    return null;
+                }
+
+                if (affKeyOffset != null)
+                {
+                    if (affKeyOffset < 0)
+                    {
+                        // Could not find the field in the written data.
+                        return null;
+                    }
+
+                    stream.Seek(affKeyOffset.Value, SeekOrigin.Begin);
+
+                    // Use ForceBinary to avoid deserializing the object. Only 
primitives will be deserialized.
+                    // For complex objects we can access BinaryObject hash 
code directly.
+                    var affKey = marsh.Unmarshal<object>(stream, 
BinaryMode.ForceBinary);
+
+                    return GetHashCode(affKey, marsh, affKeyFieldIds);
                 }
 
-                throw new IgniteException(
-                    string.Format("Failed to compute hash code for object 
'{0}' of type '{1}'", val, val.GetType()));
+                return hashCode;
             }
         }
 
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
index 8ad78a4bc44..54150542dad 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
@@ -122,24 +122,20 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
-        /// Gets the schema.
+        /// Gets the field offset.
         /// </summary>
-        /// <param name="schemaOffset">The schema offset.</param>
-        /// <returns>Current schema as a dictionary.</returns>
-        public Dictionary<int, int> GetFullSchema(int schemaOffset)
+        /// <param name="schemaOffset">Schema offset.</param>
+        /// <param name="fieldId">Field id.</param>
+        /// <returns>Field offset.</returns>
+        public int GetFieldOffset(int schemaOffset, int fieldId)
         {
-            var size = _idx - schemaOffset;
-
-            var result = new Dictionary<int, int>(size);
-
             for (int i = schemaOffset; i < _idx; i++)
             {
-                var fld = _fields[i];
-
-                result[fld.Id] = fld.Offset;
+                if (_fields[i].Id == fieldId)
+                    return _fields[i].Offset;
             }
 
-            return result;
+            return -1;
         }
     }
 }
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index bf1b2193650..a7fb495d7ea 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -71,7 +71,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Invoked when binary object writing finishes.
         /// </summary>
-        internal event Action<BinaryObjectHeader, object> OnObjectWritten;
+        internal event Action<BinaryObjectHeader, BinaryObjectSchemaHolder, 
int> OnObjectWritten;
 
         /// <summary>
         /// Write named boolean value.
@@ -1295,10 +1295,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                 BinaryObjectHeader.Write(header, _stream, pos);
 
-                if (OnObjectWritten != null)
-                {
-                    OnObjectWritten(header, obj);
-                }
+                OnObjectWritten?.Invoke(header, _schema, schemaIdx);
 
                 Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end
             }
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
index 21721468e7a..2adbdee85a3 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientFailoverSocket.cs
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Core.Impl.Client
 {
     using System;
+    using System.Collections.Concurrent;
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
@@ -96,6 +97,11 @@ namespace Apache.Ignite.Core.Impl.Client
         /** Logger. */
         private readonly ILogger _logger;
 
+        /** Key types that are not supported in partition awareness.
+         * We log warning once for those types, then bypass partition 
awareness for them. */
+        private readonly ConcurrentDictionary<Type, object> 
_partitionAwarenessUnsupportedKeyTypes =
+            new ConcurrentDictionary<Type, object>();
+
         /// <summary>
         /// Initializes a new instance of the <see 
cref="ClientFailoverSocket"/> class.
         /// </summary>
@@ -362,9 +368,8 @@ namespace Apache.Ignite.Core.Impl.Client
 
             var distributionMap = _distributionMap;
             var socketMap = _nodeSocketMap;
-            ClientCachePartitionMap cachePartMap;
 
-            if (socketMap == null || 
!distributionMap.CachePartitionMap.TryGetValue(cacheId, out cachePartMap))
+            if (socketMap == null || 
!distributionMap.CachePartitionMap.TryGetValue(cacheId, out var cachePartMap))
             {
                 return null;
             }
@@ -375,10 +380,13 @@ namespace Apache.Ignite.Core.Impl.Client
             }
 
             var partition = GetPartition(key, 
cachePartMap.PartitionNodeIds.Count, cachePartMap.KeyConfiguration);
-            var nodeId = cachePartMap.PartitionNodeIds[partition];
+            if (partition == null)
+            {
+                return null;
+            }
 
-            ClientSocket socket;
-            if (socketMap.TryGetValue(nodeId, out socket) && 
!socket.IsDisposed)
+            var nodeId = cachePartMap.PartitionNodeIds[partition.Value];
+            if (socketMap.TryGetValue(nodeId, out var socket) && 
!socket.IsDisposed)
             {
                 return socket;
             }
@@ -792,10 +800,28 @@ namespace Apache.Ignite.Core.Impl.Client
             }
         }
 
-        private int GetPartition<TKey>(TKey key, int partitionCount, 
IDictionary<int, int> keyConfiguration)
+        private int? GetPartition<TKey>(TKey key, int partitionCount, 
IDictionary<int, int> keyConfiguration)
         {
+            var keyType = key.GetType();
+            if (_partitionAwarenessUnsupportedKeyTypes.ContainsKey(keyType))
+            {
+                return null;
+            }
+
             var keyHash = BinaryHashCodeUtils.GetHashCode(key, _marsh, 
keyConfiguration);
-            return 
ClientRendezvousAffinityFunction.GetPartitionForKey(keyHash, partitionCount);
+
+            if (keyHash == null)
+            {
+                if (_partitionAwarenessUnsupportedKeyTypes.TryAdd(keyType, 
null))
+                {
+                    // Log warning only once for the given type.
+                    _logger.Warn("Failed to compute partition awareness hash 
code for type '{0}'", keyType);
+                }
+
+                return null;
+            }
+
+            return 
ClientRendezvousAffinityFunction.GetPartitionForKey(keyHash.Value, 
partitionCount);
         }
 
         private void InitSocketMap()

Reply via email to