You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by av...@apache.org on 2022/07/27 08:06:06 UTC

[ignite] branch master updated: IGNITE-15837 Read Repair should support binary keys

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

av 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 4e5dee6a479 IGNITE-15837 Read Repair should support binary keys
4e5dee6a479 is described below

commit 4e5dee6a479905b2b7f2be716cdf7840e8cd5a8f
Author: Anton Vinogradov <av...@apache.org>
AuthorDate: Wed Jul 27 11:05:55 2022 +0300

    IGNITE-15837 Read Repair should support binary keys
---
 ...sistencyRepairCorrectnessTransactionalTest.java |   8 +-
 .../processors/cache/GridCacheAdapter.java         |   6 +-
 .../cache/distributed/near/GridNearTxLocal.java    |   2 +-
 .../consistency/AbstractFullSetReadRepairTest.java |  45 +++----
 .../cache/consistency/AbstractReadRepairTest.java  |  16 ++-
 .../cache/consistency/ReadRepairDataGenerator.java | 136 +++++++++++----------
 .../testframework/junits/JUnitAssertAware.java     |   4 +-
 .../junits/common/GridCommonAbstractTest.java      |   3 +-
 8 files changed, 119 insertions(+), 101 deletions(-)

diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerConsistencyRepairCorrectnessTransactionalTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerConsistencyRepairCorrectnessTransactionalTest.java
index 1d59bc99e9b..eeb72b418c6 100644
--- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerConsistencyRepairCorrectnessTransactionalTest.java
+++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerConsistencyRepairCorrectnessTransactionalTest.java
@@ -229,14 +229,14 @@ public class GridCommandHandlerConsistencyRepairCorrectnessTransactionalTest ext
             assertEquals(EXIT_CODE_OK, execute(cmd));
         }
 
-        IgniteCache<Integer, Object> cache = rrd.cache;
+        IgniteCache<Object, Object> cache = rrd.cache;
 
-        for (Map.Entry<Integer, InconsistentMapping> dataEntry : rrd.data.entrySet()) {
-            Integer key = dataEntry.getKey();
+        for (Map.Entry<Object, InconsistentMapping> dataEntry : rrd.data.entrySet()) {
+            Object key = dataEntry.getKey();
             InconsistentMapping mapping = dataEntry.getValue();
 
             if (mapping.repairable) {
-                Object repaired = ReadRepairDataGenerator.unwrapBinaryIfNeeded(mapping.repairedBin);
+                Object repaired = gen.unwrapBinaryIfNeeded(mapping.repairedBin);
 
                 // Regular get (form primary or backup or client node).
                 assertEqualsArraysAware("Checking key=" + key, repaired, cache.get(key));
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index 59a0fe4c13f..30a63949621 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -700,7 +700,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
             /*force primary*/ !ctx.config().isReadFromBackup(),
             /*skip tx*/false,
             /*task name*/null,
-            /*deserialize binary*/false,
+            !ctx.keepBinary(),
             /*skip values*/true,
             false);
 
@@ -736,7 +736,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
             /*force primary*/ !ctx.config().isReadFromBackup(),
             /*skip tx*/false,
             /*task name*/null,
-            /*deserialize binary*/false,
+            !ctx.keepBinary(),
             opCtx != null && opCtx.recovery(),
             opCtx != null ? opCtx.readRepairStrategy() : null,
             /*skip values*/true,
@@ -5125,7 +5125,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
                 ctx.operationContextPerCall(opCtx);
 
                 try (Transaction tx = ctx.grid().transactions().txStart(PESSIMISTIC, SERIALIZABLE)) {
-                    get((K)key, null, false, false); // Repair.
+                    get((K)key, null, !ctx.keepBinary(), false); // Repair.
 
                     final GridNearTxLocal tx0 = checkCurrentTx();
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
index 06593fba05b..102f2854ae2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
@@ -3201,7 +3201,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
                     readRepairStrategy,
                     readThrough,
                     taskName,
-                    false,
+                    !keepBinary,
                     recovery,
                     expiryPlc0,
                     skipVals,
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractFullSetReadRepairTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractFullSetReadRepairTest.java
index 0af53da2554..20951ffc90f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractFullSetReadRepairTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractFullSetReadRepairTest.java
@@ -23,7 +23,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -39,11 +39,14 @@ import org.junit.Test;
  *
  */
 public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTest {
+    /** Negative key to gain null. */
+    private static final AtomicInteger decrementalKey = new AtomicInteger();
+
     /**
      *
      */
     protected static final Consumer<ReadRepairData> GET_CHECK_AND_REPAIR = (rrd) -> {
-        for (Integer key : rrd.data.keySet()) { // Once.
+        for (Object key : rrd.data.keySet()) { // Once.
             assertEqualsArraysAware(unwrapBinaryIfNeeded(rrd.data.get(key).repairedBin), get(rrd));
         }
     };
@@ -52,9 +55,9 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
      *
      */
     protected static final Consumer<ReadRepairData> GETALL_CHECK_AND_REPAIR = (rrd) -> {
-        Map<Integer, Object> res = getAll(rrd);
+        Map<Object, Object> res = getAll(rrd);
 
-        for (Integer key : rrd.data.keySet())
+        for (Object key : rrd.data.keySet())
             assertEqualsArraysAware(unwrapBinaryIfNeeded(rrd.data.get(key).repairedBin), res.get(key));
     };
 
@@ -72,12 +75,12 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
      *
      */
     protected static final Consumer<ReadRepairData> CONTAINS_CHECK_AND_REPAIR = (rrd) -> {
-        Set<Integer> keys = rrd.data.keySet();
+        Set<Object> keys = rrd.data.keySet();
 
         assert keys.size() == 1;
 
-        for (Map.Entry<Integer, InconsistentMapping> entry : rrd.data.entrySet()) { // Once.
-            Integer key = entry.getKey();
+        for (Map.Entry<Object, InconsistentMapping> entry : rrd.data.entrySet()) { // Once.
+            Object key = entry.getKey();
 
             boolean res = rrd.async ?
                 rrd.cache.withReadRepair(rrd.strategy).containsKeyAsync(key).get() :
@@ -91,7 +94,7 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
      *
      */
     protected static final Consumer<ReadRepairData> CONTAINS_ALL_CHECK_AND_REPAIR = (rrd) -> {
-        Set<Integer> keys = rrd.data.keySet();
+        Set<Object> keys = rrd.data.keySet();
 
         assert !keys.isEmpty();
 
@@ -108,16 +111,16 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
      *
      */
     private static Object get(ReadRepairData rrd) {
-        Set<Integer> keys = rrd.data.keySet();
+        Set<Object> keys = rrd.data.keySet();
 
         assert keys.size() == 1;
 
-        Integer key = keys.iterator().next();
+        Object key = keys.iterator().next();
 
         Object res;
 
         if (rrd.raw) {
-            CacheEntry<Integer, Object> rawEntry = rrd.async ?
+            CacheEntry<Object, Object> rawEntry = rrd.async ?
                 rrd.cache.withReadRepair(rrd.strategy).getEntryAsync(key).get() :
                 rrd.cache.withReadRepair(rrd.strategy).getEntry(key);
 
@@ -134,22 +137,22 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
     /**
      *
      */
-    private static Map<Integer, Object> getAll(ReadRepairData rrd) {
-        Set<Integer> keys = rrd.data.keySet();
+    private static Map<Object, Object> getAll(ReadRepairData rrd) {
+        Set<Object> keys = rrd.data.keySet();
 
         assert !keys.isEmpty();
 
-        Map<Integer, Object> objs;
+        Map<Object, Object> objs;
 
         if (rrd.raw) {
-            Collection<CacheEntry<Integer, Object>> entryRes =
+            Collection<CacheEntry<Object, Object>> entryRes =
                 rrd.async ?
                     rrd.cache.withReadRepair(rrd.strategy).getEntriesAsync(keys).get() :
                     rrd.cache.withReadRepair(rrd.strategy).getEntries(keys);
 
             objs = new HashMap<>();
 
-            for (CacheEntry<Integer, Object> entry : entryRes)
+            for (CacheEntry<Object, Object> entry : entryRes)
                 objs.put(entry.getKey(), entry.getValue());
         }
         else {
@@ -193,12 +196,12 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
             rrd.cache,
             rrd.data.entrySet().stream().collect(
                 Collectors.toMap(
-                    e -> -1 * e.getKey(), // Negative key to gain null.
+                    e -> decrementalKey.decrementAndGet(), // Negative key to gain null.
                     Map.Entry::getValue,
                     (k, v) -> {
                         throw new IllegalStateException(String.format("Duplicate key %s", k));
                     },
-                    TreeMap::new)),
+                    HashMap::new)),
             rrd.raw,
             rrd.async,
             rrd.strategy,
@@ -212,8 +215,8 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
         (rrd, e) -> {
             boolean raw = rrd.raw;
 
-            for (Map.Entry<Integer, InconsistentMapping> entry : rrd.data.entrySet()) {
-                Integer key = entry.getKey();
+            for (Map.Entry<Object, InconsistentMapping> entry : rrd.data.entrySet()) {
+                Object key = entry.getKey();
 
                 // Checking only repaired entries, while entries listed at exception were not repaired.
                 if (e != null && (e.irreparableKeys().contains(key) ||
@@ -223,7 +226,7 @@ public abstract class AbstractFullSetReadRepairTest extends AbstractReadRepairTe
                 Object res;
 
                 if (raw) {
-                    CacheEntry<Integer, Object> rawEntry = rrd.cache.getEntry(key);
+                    CacheEntry<Object, Object> rawEntry = rrd.cache.getEntry(key);
 
                     res = rawEntry != null ? rawEntry.getValue() : null;
                 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractReadRepairTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractReadRepairTest.java
index 8ec7a920e86..6755f9495c2 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractReadRepairTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/AbstractReadRepairTest.java
@@ -68,7 +68,7 @@ public abstract class AbstractReadRepairTest extends GridCommonAbstractTest {
     protected static volatile List<Ignite> clsAwareNodes;
 
     /** Generator. */
-    private static volatile ReadRepairDataGenerator gen;
+    protected static volatile ReadRepairDataGenerator gen;
 
     /** Backups count. */
     protected Integer backupsCount() {
@@ -207,9 +207,11 @@ public abstract class AbstractReadRepairTest extends GridCommonAbstractTest {
         Map<Object, Map<ClusterNode, CacheConsistencyViolationEvent.EntryInfo>> evtEntries = new HashMap<>();
         Map<Object, Object> evtRepaired = new HashMap<>();
 
-        Map<Integer, InconsistentMapping> inconsistent = rrd.data.entrySet().stream()
+        Map<Object, InconsistentMapping> inconsistent = rrd.data.entrySet().stream()
             .filter(entry -> !entry.getValue().consistent)
-            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+            .collect(Collectors.toMap(
+                entry -> gen.toBinary(entry.getKey()), // Events are always contain binary keys, converting expectations.
+                Map.Entry::getValue));
 
         while (!evtEntries.keySet().equals(inconsistent.keySet())) {
             if (!evtDeq.isEmpty()) {
@@ -228,10 +230,12 @@ public abstract class AbstractReadRepairTest extends GridCommonAbstractTest {
             }
         }
 
-        for (Map.Entry<Integer, InconsistentMapping> mapping : inconsistent.entrySet()) {
-            Integer key = mapping.getKey();
+        for (Map.Entry<Object, InconsistentMapping> mapping : inconsistent.entrySet()) {
+            Object key = mapping.getKey();
+
             Object repairedBin = mapping.getValue().repairedBin;
             Object primaryBin = mapping.getValue().primaryBin;
+
             boolean repairable = mapping.getValue().repairable;
 
             if (!repairable)
@@ -290,7 +294,7 @@ public abstract class AbstractReadRepairTest extends GridCommonAbstractTest {
      * @param obj Object.
      */
     protected static Object unwrapBinaryIfNeeded(Object obj) {
-        return ReadRepairDataGenerator.unwrapBinaryIfNeeded(obj);
+        return gen.unwrapBinaryIfNeeded(obj);
     }
 
     /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/ReadRepairDataGenerator.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/ReadRepairDataGenerator.java
index a3def14f145..a18bda2f8ef 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/ReadRepairDataGenerator.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/consistency/ReadRepairDataGenerator.java
@@ -25,7 +25,6 @@ import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.TreeMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiFunction;
@@ -36,6 +35,7 @@ import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteBinary;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.ReadRepairStrategy;
 import org.apache.ignite.internal.GridKernalContext;
@@ -77,10 +77,10 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
     private final ClassLoader extClsLdr;
 
     /** Primary node. */
-    private final BiFunction<Integer, String, Ignite> primaryNode;
+    private final BiFunction<Object, String, Ignite> primaryNode;
 
     /** Backup nodes. */
-    private final BiFunction<Integer, String, List<Ignite>> backupNodes;
+    private final BiFunction<Object, String, List<Ignite>> backupNodes;
 
     /** Server nodes count. */
     private final Supplier<Integer> serverNodesCnt;
@@ -101,8 +101,8 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
         String cacheName,
         List<Ignite> clsAwareNodes,
         ClassLoader extClsLdr,
-        BiFunction<Integer, String, Ignite> primaryNode,
-        BiFunction<Integer, String, List<Ignite>> backupNodes,
+        BiFunction<Object, String, Ignite> primaryNode,
+        BiFunction<Object, String, List<Ignite>> backupNodes,
         Supplier<Integer> serverNodesCnt,
         Supplier<Integer> backupsCnt) {
         this.cacheName = cacheName;
@@ -137,7 +137,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
         boolean binary,
         ReadRepairStrategy strategy,
         Consumer<ReadRepairData> c) throws Exception {
-        IgniteCache<Integer, Object> cache = initiator.getOrCreateCache(cacheName);
+        IgniteCache<Object, Object> cache = initiator.getOrCreateCache(cacheName);
 
         ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
@@ -146,36 +146,30 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
         for (int i = 0; i < rnd.nextInt(1, 10); i++) {
             ReadRepairStrategy keyStrategy = strategy != null ? strategy : strategies[rnd.nextInt(strategies.length)];
 
-            Map<Integer, InconsistentMapping> results = new TreeMap<>(); // Sorted to avoid warning.
+            Map<Object, InconsistentMapping> results = new HashMap<>();
 
             try {
                 for (int j = 0; j < cnt; j++) {
-                    int curKey = incrementalKey.incrementAndGet();
+                    Object curKey = wrapTestKeyIfNeeded(rnd.nextBoolean(), incrementalKey.incrementAndGet());
 
-                    InconsistentMapping res = setDifferentValuesForSameKey(curKey, misses, nulls, keyStrategy);
-
-                    results.put(curKey, res);
-                }
-
-                for (Ignite node : G.allGrids()) { // Check that cache filled properly.
-                    Map<Integer, Object> all =
-                        node.getOrCreateCache(cacheName).<Integer, Object>withKeepBinary().getAll(results.keySet());
+                    if (binary)
+                        curKey = toBinary(curKey);
 
-                    for (Map.Entry<Integer, Object> entry : all.entrySet()) {
-                        Integer key = entry.getKey();
-                        Object val = entry.getValue();
+                    InconsistentMapping res = setDifferentValuesForSameKey(curKey, misses, nulls, keyStrategy);
 
-                        T2<Object, GridCacheVersion> valVer = results.get(key).mappingBin.get(node);
+                    for (Ignite node : G.allGrids()) { // Check that cache filled properly.
+                        T2<Object, GridCacheVersion> valVer = res.mappingBin.get(node);
 
-                        Object exp;
+                        Object exp = valVer != null ?
+                            valVer.get1() : // Should read from itself (backup or primary).
+                            res.primaryBin; // Or read from primary (when not a partition owner).
 
-                        if (valVer != null)
-                            exp = valVer.get1(); // Should read from itself (backup or primary).
-                        else
-                            exp = results.get(key).primaryBin; // Or read from primary (when not a partition owner).
+                        Object val = node.getOrCreateCache(cacheName).withKeepBinary().get(curKey);
 
                         assertEqualsArraysAware(exp, val);
                     }
+
+                    results.put(curKey, res);
                 }
 
                 c.accept(new ReadRepairData(cache, results, raw, async, keyStrategy, binary));
@@ -188,7 +182,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
                     .append(", strategy=").append(keyStrategy)
                     .append("]\n");
 
-                for (Map.Entry<Integer, InconsistentMapping> entry : results.entrySet()) {
+                for (Map.Entry<Object, InconsistentMapping> entry : results.entrySet()) {
                     sb.append("Key: ").append(entry.getKey()).append("\n");
 
                     InconsistentMapping mapping = entry.getValue();
@@ -217,6 +211,15 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
         }
     }
 
+    /**
+     *
+     */
+    public Object toBinary(Object obj) {
+        IgniteBinary igniteBinary = clsAwareNodes.get(0).binary();
+
+        return igniteBinary.toBinary(obj);
+    }
+
     /**
      * @param obj Object.
      */
@@ -239,7 +242,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
      *
      */
     private InconsistentMapping setDifferentValuesForSameKey(
-        int key,
+        Object key,
         boolean misses,
         boolean nulls,
         ReadRepairStrategy strategy) throws Exception {
@@ -495,10 +498,8 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
             }
         }
 
-        IgniteBinary igniteBinary = clsAwareNodes.get(0).binary();
-
-        Object primValBin = igniteBinary.toBinary(primVal);
-        Object repairedBin = igniteBinary.toBinary(unwrapArrayIfNeeded(repaired));
+        Object primValBin = toBinary(primVal);
+        Object repairedBin = toBinary(unwrapArrayIfNeeded(repaired));
 
         Map<Ignite, T2<Object, GridCacheVersion>> mappingBin = mapping.entrySet().stream().collect(
             Collectors.toMap(
@@ -506,7 +507,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
                 (entry) -> {
                     T2<Object, GridCacheVersion> t2 = entry.getValue();
 
-                    return new T2<>(igniteBinary.toBinary(unwrapArrayIfNeeded(t2.getKey())), t2.getValue());
+                    return new T2<>(toBinary(unwrapArrayIfNeeded(t2.getKey())), t2.getValue());
                 }));
 
         return new InconsistentMapping(mappingBin, primValBin, repairedBin, repairable, consistent);
@@ -544,15 +545,28 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
     }
 
     /**
-     * @param wrap Wrap.
-     * @param val  Value.
+     *
+     */
+    private Object wrapTestKeyIfNeeded(boolean wrap, Integer key) {
+        return wrapIfNeeded(wrap, true, key);
+    }
+
+    /**
+     *
+     */
+    private Object wrapTestValueIfNeeded(boolean wrap, Integer val) {
+        return wrapIfNeeded(wrap, false, val);
+    }
+
+    /**
+     *
      */
-    private Object wrapTestValueIfNeeded(boolean wrap, Integer val) throws ReflectiveOperationException {
+    private Object wrapIfNeeded(boolean wrap, boolean key, Integer val) {
         if (wrap) {
-            int type = val % 7;
+            List<Supplier<Object>> wrapClos = new ArrayList<>();
 
-            switch (type) {
-                case 0:
+            wrapClos.add(() -> {
+                try {
                     // Some nodes will be unable to deserialize this object.
                     // Checking that Read Repair feature cause no `class not found` problems.
                     Class<?> clazz = extClsLdr.loadClass("org.apache.ignite.tests.p2p.cache.PersonKey");
@@ -562,28 +576,24 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
                     GridTestUtils.setFieldValue(obj, "id", val);
 
                     return obj;
+                }
+                catch (Exception e) {
+                    throw new IgniteException(e);
+                }
+            });
 
-                case 1:
-                    return new Object[] {val};
-
-                case 2:
-                    return new Object[][] {{val}, {val}};
-
-                case 3:
-                    return new int[] {val};
-
-                case 4:
-                    return Collections.singletonMap(val, val);
-
-                case 5:
-                    return Collections.singletonList(val);
+            wrapClos.add(() -> Collections.singletonMap(val, val));
+            wrapClos.add(() -> Collections.singletonList(val));
+            wrapClos.add(() -> Collections.singleton(val));
 
-                case 6:
-                    return Collections.singleton(val);
+            wrapClos.add(() -> new int[] {val});
 
-                default:
-                    throw new IllegalStateException();
+            if (!key) {
+                wrapClos.add(() -> new Object[] {val});
+                wrapClos.add(() -> new Object[][] {{val}, {val}});
             }
+
+            return wrapClos.get(val % wrapClos.size()).get();
         }
         else
             return val;
@@ -592,7 +602,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
     /**
      * @param obj Object.
      */
-    public static Object unwrapBinaryIfNeeded(Object obj) {
+    public Object unwrapBinaryIfNeeded(Object obj) {
         if (obj instanceof BinaryObject) {
             BinaryObject valObj = (BinaryObject)obj;
 
@@ -606,7 +616,7 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
      * @param ctx Context.
      * @param val Value.
      */
-    byte[] marshalValue(CacheObjectContext ctx, Object val) throws IgniteCheckedException {
+    private byte[] marshalValue(CacheObjectContext ctx, Object val) throws IgniteCheckedException {
         IgniteCacheObjectProcessor clsAwareProc = ((IgniteEx)clsAwareNodes.get(0)).context().cacheObjects();
 
         return clsAwareProc.marshal(ctx, val);
@@ -617,10 +627,10 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
      */
     public static final class ReadRepairData {
         /** Initiator's cache. */
-        public final IgniteCache<Integer, Object> cache;
+        public final IgniteCache<Object, Object> cache;
 
-        /** Generated data across topology per key mapping. */
-        public final Map<Integer, InconsistentMapping> data;
+        /** Generated data across topology per (binary) key mapping. */
+        public final Map<Object, InconsistentMapping> data;
 
         /** Raw read flag. True means required GetEntry() instead of get(). */
         public final boolean raw;
@@ -638,8 +648,8 @@ public class ReadRepairDataGenerator extends JUnitAssertAware {
          *
          */
         public ReadRepairData(
-            IgniteCache<Integer, Object> cache,
-            Map<Integer, InconsistentMapping> data,
+            IgniteCache<Object, Object> cache,
+            Map<Object, InconsistentMapping> data,
             boolean raw,
             boolean async,
             ReadRepairStrategy strategy,
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/JUnitAssertAware.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/JUnitAssertAware.java
index 3423e3cfb35..3fdcb125c72 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/JUnitAssertAware.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/JUnitAssertAware.java
@@ -212,9 +212,9 @@ public class JUnitAssertAware {
 
     /** Check arrays equality as well as objects equality. */
     protected static void assertEqualsArraysAware(String msg, Object exp, Object actual) {
-        if (exp instanceof Object[])
+        if (exp instanceof Object[] && actual instanceof Object[])
             Assert.assertArrayEquals((Object[])exp, (Object[])actual);
-        else if (U.isPrimitiveArray(exp))
+        else if (U.isPrimitiveArray(exp) && U.isPrimitiveArray(actual))
             Assert.assertArrayEquals(new Object[] {exp}, new Object[] {actual}); // Hack to compare primitive arrays.
         else
             Assert.assertEquals(exp, actual);
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
index 14d33c13899..6c52d1e1f35 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java
@@ -1898,7 +1898,8 @@ public abstract class GridCommonAbstractTest extends GridAbstractTest {
             (exp.size() == act.size()));
 
         for (T obj : exp)
-            assertEquals("Collections are not equal (element " + obj + " frequency is different):",
+            assertEquals("Collections are not equal (element " + obj + " frequency is different)." +
+                    "\nCollections: " + exp + ", " + act,
                 Collections.frequency(exp, obj), Collections.frequency(act, obj));
     }