Aha! After more investigation I found GetHashCode() can return a negative
value, leading to a negative partition number result from GetPartition, and
the resulting array index exception many calls lower in the stack.
Changing GetPartition to the following corrects the issue
public int GetPartition(object key) =>
Math.Abs(((NonSpatialAffinityKey)key).ProjectID.GetHashCode()) % Partitions;
Now I just need to use a stable GUID to hash function rather than the .Net
one.
Apologies for the scare 😊
Thanks,
Raymond.
*From:* Raymond Wilson [mailto:[email protected]]
*Sent:* Friday, May 11, 2018 2:37 PM
*To:* '[email protected]' <[email protected]>
*Subject:* RE: Possible bug in PutAll() in Ignite 2.4, .Net client
I have previously used the same logic using a long instead of a Guid
without this issue.
*From:* Raymond Wilson [mailto:[email protected]
<[email protected]>]
*Sent:* Friday, May 11, 2018 2:36 PM
*To:* '[email protected]' <[email protected]>
*Subject:* RE: Possible bug in PutAll() in Ignite 2.4, .Net client
I have tried replacing the PutAll() with two Put()s, like this:
cache.Put(key1, new byte[100]);
cache.Put(key2, new byte[100]);
The first Put throws this exception:
*Name*
*Value*
*Type*
â–¶
$exception
{Apache.Ignite.Core.Cache.CacheException: class
org.apache.ignite.IgniteCheckedException: -6 --->
Apache.Ignite.Core.Common.IgniteException: -6 --->
Apache.Ignite.Core.Common.JavaException: javax.cache.CacheException: class
org.apache.ignite.IgniteCheckedException: -6 at
org.apache.ignite.internal.processors.cache.GridCacheUtils.convertToCacheException(GridCacheUtils.java:1294)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.cacheException(IgniteCacheProxyImpl.java:1673)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.put(IgniteCacheProxyImpl.java:1029)
at
org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.put(GatewayProtectedCacheProxy.java:886)
at
org.apache.ignite.internal.processors.platform.cache.PlatformCache.processInStreamOutLong(PlatformCache.java:405)
at
org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutLong(PlatformTargetProxyImpl.java:67)
Caused by: class org.apache.ignite.IgniteCheckedException: -6 at
org.apache.ignite.internal.util.IgniteUtils.cast(IgniteUtils.java:7244) at
org.apache.ignite.internal.util.future.GridFutureAdapter.resolve(GridFutureAdapter.java:259)
at
org.apache.ignite.internal.util.future.GridFutureAdapter.get0(GridFutureAdapter.java:171)
at
org.apache.ignite.internal.util.future.GridFutureAdapter.get(GridFutureAdapter.java:140)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.put0(GridDhtAtomicCache.java:613)
at
org.apache.ignite.internal.processors.cache.GridCacheAdapter.put(GridCacheAdapter.java:2369)
at
org.apache.ignite.internal.processors.cache.GridCacheAdapter.put(GridCacheAdapter.java:2346)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.put(IgniteCacheProxyImpl.java:1026)
... 3 more Caused by: java.lang.ArrayIndexOutOfBoundsException: -6 at
java.util.ArrayList.elementData(ArrayList.java:418) at
java.util.ArrayList.get(ArrayList.java:431) at
org.apache.ignite.internal.processors.affinity.GridAffinityAssignment.get(GridAffinityAssignment.java:156)
at
org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentCache.nodes(GridAffinityAssignmentCache.java:509)
at
org.apache.ignite.internal.processors.cache.GridCacheAffinityManager.nodesByPartition(GridCacheAffinityManager.java:225)
at
org.apache.ignite.internal.processors.cache.GridCacheAffinityManager.nodesByKey(GridCacheAffinityManager.java:208)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicSingleUpdateFuture.mapSingleUpdate(GridNearAtomicSingleUpdateFuture.java:559)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicSingleUpdateFuture.map(GridNearAtomicSingleUpdateFuture.java:454)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicSingleUpdateFuture.mapOnTopology(GridNearAtomicSingleUpdateFuture.java:443)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicAbstractUpdateFuture.map(GridNearAtomicAbstractUpdateFuture.java:248)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.update0(GridDhtAtomicCache.java:1117)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.put0(GridDhtAtomicCache.java:606)
... 6 more --- End of inner exception stack trace --- --- End of inner
exception stack trace --- at
Apache.Ignite.Core.Impl.PlatformJniTarget.InStreamOutLong[TR](Int32 type,
Action`1 outAction, Func`3 inAction, Func`2 readErrorAction) at
Apache.Ignite.Core.Impl.PlatformTargetAdapter.DoOutInOpX(Int32 type,
Action`1 outAction, Func`2 inErrorAction) at
Apache.Ignite.Core.Impl.Cache.CacheImpl`2.Put(TK key, TV val) at
RaptorClassLibrary.Tests.netcore.Affinity.AffinityTests.Test_NonSpatialAffintyKey_MutableGrid_IgniteException()
in
C:\Dev\VSS.TRex\tests\RaptorClassLibrary.Tests.netcore\Affinity\AffinityTests.cs:line
104}
Apache.Ignite.Core.Cache.CacheException
*From:* Raymond Wilson [mailto:[email protected]
<[email protected]>]
*Sent:* Friday, May 11, 2018 2:31 PM
*To:* '[email protected]' <[email protected]>
*Subject:* Possible bug in PutAll() in Ignite 2.4, .Net client
I have run into an issue using an AffinityFunction with a Guid in the key.
The complete reproducer is included below as an XUnit unit test.
I do know about the [AffinityKeyMapped] attribute, but I want to have
different behaviour for these keys depending on context (sometimes I want
them partitioned, and sometimes I want them replicated), so I am using
AffinityFunctions to achieve this. I am not aware of any way of defining
the partition key mapping aspect of GetPartition(), so I have what I think
is the default mapping logic for mapping partitions to nodes in
AssignPartitions.
At the point where the code below executes the PutAll(), the following
exception is generated:
*Name*
*Value*
*Type*
â–¶
$exception
{Apache.Ignite.Core.Cache.CacheException: class
org.apache.ignite.IgniteCheckedException: -889 --->
Apache.Ignite.Core.Common.IgniteException: -889 --->
Apache.Ignite.Core.Common.JavaException: javax.cache.CacheException: class
org.apache.ignite.IgniteCheckedException: -889 at
org.apache.ignite.internal.processors.cache.GridCacheUtils.convertToCacheException(GridCacheUtils.java:1294)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.cacheException(IgniteCacheProxyImpl.java:1673)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.putAll(IgniteCacheProxyImpl.java:1092)
at
org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.putAll(GatewayProtectedCacheProxy.java:942)
at
org.apache.ignite.internal.processors.platform.cache.PlatformCache.processInStreamOutLong(PlatformCache.java:421)
at
org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutLong(PlatformTargetProxyImpl.java:67)
Caused by: class org.apache.ignite.IgniteCheckedException: -889 at
org.apache.ignite.internal.util.IgniteUtils.cast(IgniteUtils.java:7244) at
org.apache.ignite.internal.util.future.GridFutureAdapter.resolve(GridFutureAdapter.java:259)
at
org.apache.ignite.internal.util.future.GridFutureAdapter.get0(GridFutureAdapter.java:171)
at
org.apache.ignite.internal.util.future.GridFutureAdapter.get(GridFutureAdapter.java:140)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.putAll0(GridDhtAtomicCache.java:656)
at
org.apache.ignite.internal.processors.cache.GridCacheAdapter.putAll(GridCacheAdapter.java:2808)
at
org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.putAll(IgniteCacheProxyImpl.java:1089)
... 3 more Caused by: java.lang.ArrayIndexOutOfBoundsException: -889 at
java.util.ArrayList.elementData(ArrayList.java:418) at
java.util.ArrayList.get(ArrayList.java:431) at
org.apache.ignite.internal.processors.affinity.GridAffinityAssignment.get(GridAffinityAssignment.java:156)
at
org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentCache.nodes(GridAffinityAssignmentCache.java:509)
at
org.apache.ignite.internal.processors.cache.GridCacheAffinityManager.nodesByPartition(GridCacheAffinityManager.java:225)
at
org.apache.ignite.internal.processors.cache.GridCacheAffinityManager.nodesByKey(GridCacheAffinityManager.java:208)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.mapUpdate(GridNearAtomicUpdateFuture.java:998)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.map(GridNearAtomicUpdateFuture.java:764)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.mapOnTopology(GridNearAtomicUpdateFuture.java:664)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicAbstractUpdateFuture.map(GridNearAtomicAbstractUpdateFuture.java:248)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.updateAll0(GridDhtAtomicCache.java:1069)
at
org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.putAll0(GridDhtAtomicCache.java:648)
... 5 more --- End of inner exception stack trace --- --- End of inner
exception stack trace --- at
Apache.Ignite.Core.Impl.PlatformJniTarget.InStreamOutLong[TR](Int32 type,
Action`1 outAction, Func`3 inAction, Func`2 readErrorAction) at
Apache.Ignite.Core.Impl.PlatformTargetAdapter.DoOutInOpX(Int32 type,
Action`1 outAction, Func`2 inErrorAction) at
Apache.Ignite.Core.Impl.Cache.CacheImpl`2.PutAll(IEnumerable`1 vals) at
RaptorClassLibrary.Tests.netcore.Affinity.AffinityTests.Test_NonSpatialAffintyKey_MutableGrid_IgniteException()
in
C:\Dev\VSS.TRex\tests\RaptorClassLibrary.Tests.netcore\Affinity\AffinityTests.cs:line
104}
Apache.Ignite.Core.Cache.CacheException
Reproducer code follows:
using System;
using System.Collections.Generic;
using System.Linq;
using Apache.Ignite.Core;
using Apache.Ignite.Core.Cache;
using Apache.Ignite.Core.Cache.Affinity;
using Apache.Ignite.Core.Cache.Configuration;
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Configuration;
using Xunit;
namespace RaptorClassLibrary.Tests.netcore.Affinity
{
[Serializable]
public class MutableNonSpatialAffinityFunction : IAffinityFunction
{
public int Partitions => 1024;
public void RemoveNode(Guid nodeId) { }
public IEnumerable<IEnumerable<IClusterNode>>
AssignPartitions(AffinityFunctionContext context)
{
List<List<IClusterNode>> result = Enumerable.Range(0,
Partitions).Select(x => new List<IClusterNode>()).ToList();
List<IClusterNode> Nodes =
context.CurrentTopologySnapshot.ToList();
if (Nodes.Count > 0)
{
for (int partitionIndex = 0; partitionIndex < Partitions;
partitionIndex++)
result[partitionIndex].Add(Nodes[Partitions %
Nodes.Count]);
}
return result;
}
public int GetPartition(object key) =>
((NonSpatialAffinityKey)key).ProjectID.GetHashCode() % Partitions;
}
[Serializable]
public struct NonSpatialAffinityKey
{
public Guid ProjectID { get; set; }
public string KeyName { get; set; }
public NonSpatialAffinityKey(Guid projectID, string keyName)
{
ProjectID = projectID;
KeyName = keyName;
}
public override string ToString() => $"{ProjectID}-{KeyName}";
}
public class AffinityTests
{
private static IIgnite ignite;
private static void ConfigureGrid(IgniteConfiguration cfg)
{
cfg.IgniteInstanceName = "MyGrid3";
}
private static void EnsureServer()
{
IgniteConfiguration cfg = new IgniteConfiguration();
ConfigureGrid(cfg);
ignite = Ignition.Start(cfg);
}
[Fact]
public void Test_NonSpatialAffintyKey_MutableGrid_IgniteException()
{
EnsureServer();
ICache<NonSpatialAffinityKey, byte[]> cache =
ignite.GetOrCreateCache<NonSpatialAffinityKey, byte[]>(
new CacheConfiguration
{
Name = "MyCache",
CacheMode = CacheMode.Partitioned,
AffinityFunction = new
MutableNonSpatialAffinityFunction(),
});
NonSpatialAffinityKey key1 = new NonSpatialAffinityKey
{ProjectID = Guid.NewGuid(), KeyName = "bob1"};
NonSpatialAffinityKey key2 = new NonSpatialAffinityKey
{ProjectID = Guid.NewGuid(), KeyName = "bob2"};
///////// Exception occurs at this line
cache.PutAll(new List<KeyValuePair<NonSpatialAffinityKey, byte
[]>>
{
new KeyValuePair<NonSpatialAffinityKey, byte[]>(key1, new
byte[100]),
new KeyValuePair<NonSpatialAffinityKey, byte[]>(key2, new
byte[100])
});
Assert.True(true);
}
}
}