IGNITE-8752 Deadlock when registering binary metadata while holding topology 
read lock - Fixes #4237.

Signed-off-by: Ivan Rakov <ira...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/929a12d4
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/929a12d4
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/929a12d4

Branch: refs/heads/ignite-8446
Commit: 929a12d4a9ad156cd6253204112e742cc0fb9c41
Parents: 67a2aac
Author: Ilya Lantukh <ilant...@gridgain.com>
Authored: Wed Jun 27 14:53:05 2018 +0300
Committer: Ivan Rakov <ira...@apache.org>
Committed: Wed Jun 27 14:53:05 2018 +0300

----------------------------------------------------------------------
 .../internal/UnregisteredClassException.java    | 74 ++++++++++++++++++++
 .../ignite/internal/binary/BinaryContext.java   | 20 ++++--
 .../internal/binary/BinaryEnumObjectImpl.java   |  2 +-
 .../internal/binary/BinaryMarshaller.java       |  2 +-
 .../internal/binary/BinaryReaderExImpl.java     |  2 +-
 .../ignite/internal/binary/BinaryUtils.java     |  4 +-
 .../internal/binary/BinaryWriterExImpl.java     | 28 ++++++--
 .../internal/binary/GridBinaryMarshaller.java   |  5 +-
 .../binary/builder/BinaryBuilderEnum.java       |  2 +-
 .../binary/builder/BinaryBuilderSerializer.java |  2 +-
 .../builder/BinaryEnumArrayLazyValue.java       |  2 +-
 .../builder/BinaryObjectArrayLazyValue.java     |  2 +-
 .../binary/builder/BinaryObjectBuilderImpl.java |  2 +-
 .../client/thin/ClientBinaryMarshaller.java     |  2 +-
 .../CacheDefaultBinaryAffinityKeyMapper.java    |  2 +-
 .../processors/cache/CacheGroupContext.java     | 10 +++
 .../processors/cache/GridCacheContext.java      |  2 +-
 .../processors/cache/GridCacheReturn.java       |  5 ++
 .../binary/CacheObjectBinaryProcessor.java      |  3 +-
 .../binary/CacheObjectBinaryProcessorImpl.java  | 43 +++++++-----
 .../cache/binary/IgniteBinaryImpl.java          |  2 +-
 .../dht/GridClientPartitionTopology.java        |  5 ++
 .../dht/GridDhtPartitionTopology.java           |  4 ++
 .../dht/GridDhtPartitionTopologyImpl.java       |  5 ++
 .../dht/atomic/GridDhtAtomicCache.java          | 70 +++++++++++-------
 .../cacheobject/IgniteCacheObjectProcessor.java | 11 +++
 .../IgniteCacheObjectProcessorImpl.java         |  6 ++
 .../util/StripedCompositeReadWriteLock.java     | 25 ++++++-
 .../IgniteCacheEntryProcessorCallTest.java      |  5 ++
 29 files changed, 273 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/UnregisteredClassException.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/UnregisteredClassException.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/UnregisteredClassException.java
new file mode 100644
index 0000000..6da7daa
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/UnregisteredClassException.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal;
+
+import org.apache.ignite.IgniteException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Exception thrown during serialization if class isn't registered and it's 
registration isn't allowed.
+ */
+public class UnregisteredClassException extends IgniteException {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** */
+    private final Class cls;
+
+    /**
+     * @param cls Class that isn't registered.
+     */
+    public UnregisteredClassException(Class cls) {
+        this.cls = cls;
+    }
+
+    /**
+     * @param msg Error message.
+     * @param cls Class that isn't registered.
+     */
+    public UnregisteredClassException(String msg, Class cls) {
+        super(msg);
+        this.cls = cls;
+    }
+
+    /**
+     * @param cause Exception cause.
+     * @param cls Class that isn't registered.
+     */
+    public UnregisteredClassException(Throwable cause, Class cls) {
+        super(cause);
+        this.cls = cls;
+    }
+
+    /**
+     * @param msg Error message.
+     * @param cause Exception cause.
+     * @param cls Class that isn't registered.
+     */
+    public UnregisteredClassException(String msg, @Nullable Throwable cause, 
Class cls) {
+        super(msg, cause);
+        this.cls = cls;
+    }
+
+    /**
+     * @return Class that isn't registered.
+     */
+    public Class cls() {
+        return cls;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
index 2337696..0121570 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
@@ -48,6 +48,7 @@ import java.util.jar.JarFile;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.UnregisteredClassException;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.binary.BinaryBasicIdMapper;
 import org.apache.ignite.binary.BinaryBasicNameMapper;
@@ -610,17 +611,22 @@ public class BinaryContext {
 
     /**
      * @param cls Class.
+     * @param failIfUnregistered Throw exception if class isn't registered.
      * @return Class descriptor.
      * @throws BinaryObjectException In case of error.
      */
-    public BinaryClassDescriptor descriptorForClass(Class<?> cls, boolean 
deserialize)
+    public BinaryClassDescriptor descriptorForClass(Class<?> cls, boolean 
deserialize, boolean failIfUnregistered)
         throws BinaryObjectException {
         assert cls != null;
 
         BinaryClassDescriptor desc = descByCls.get(cls);
 
-        if (desc == null)
+        if (desc == null) {
+            if (failIfUnregistered)
+                throw new UnregisteredClassException(cls);
+
             desc = registerClassDescriptor(cls, deserialize);
+        }
         else if (!desc.registered()) {
             if (!desc.userType()) {
                 BinaryClassDescriptor desc0 = new BinaryClassDescriptor(
@@ -652,8 +658,12 @@ public class BinaryContext {
                     return desc0;
                 }
             }
-            else
+            else {
+                if (failIfUnregistered)
+                    throw new UnregisteredClassException(cls);
+
                 desc = registerUserClassDescriptor(desc);
+            }
         }
 
         return desc;
@@ -1176,8 +1186,8 @@ public class BinaryContext {
     /**
      * Register "type ID to class name" mapping on all nodes to allow for 
mapping requests resolution form client.
      * Other {@link BinaryContext}'s "register" methods and method
-     * {@link BinaryContext#descriptorForClass(Class, boolean)} already call 
this functionality so use this method
-     * only when registering class names whose {@link Class} is unknown.
+     * {@link BinaryContext#descriptorForClass(Class, boolean, boolean)} 
already call this functionality
+     * so use this method only when registering class names whose {@link 
Class} is unknown.
      *
      * @param typeId Type ID.
      * @param clsName Class Name.

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
index 12a0fc3..2751695 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
@@ -437,6 +437,6 @@ public class BinaryEnumObjectImpl implements 
BinaryObjectEx, Externalizable, Cac
      * binary enum.
      */
     public boolean isTypeEquals(final Class<?> cls) {
-        return ctx.descriptorForClass(cls, false).typeId() == typeId();
+        return ctx.descriptorForClass(cls, false, false).typeId() == typeId();
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMarshaller.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMarshaller.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMarshaller.java
index dfc726e..bfb0e10 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMarshaller.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryMarshaller.java
@@ -79,7 +79,7 @@ public class BinaryMarshaller extends 
AbstractNodeNameAwareMarshaller {
 
     /** {@inheritDoc} */
     @Override protected byte[] marshal0(@Nullable Object obj) throws 
IgniteCheckedException {
-        return impl.marshal(obj);
+        return impl.marshal(obj, false);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
index f88e3c3..ab1f874 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
@@ -265,7 +265,7 @@ public class BinaryReaderExImpl implements BinaryReader, 
BinaryRawReaderEx, Bina
 
                 if (forUnmarshal) {
                     // Registers class by type ID, at least locally if the 
cache is not ready yet.
-                    desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, 
ctx, ldr, typeId0), false);
+                    desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, 
ctx, ldr, typeId0), false, false);
 
                     typeId = desc.typeId();
                 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
index 082cc20..553d8e5 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
@@ -1625,7 +1625,7 @@ public class BinaryUtils {
             }
 
             // forces registering of class by type id, at least locally
-            ctx.descriptorForClass(cls, true);
+            ctx.descriptorForClass(cls, true, false);
         }
 
         return cls;
@@ -1655,7 +1655,7 @@ public class BinaryUtils {
             }
 
             // forces registering of class by type id, at least locally
-            ctx.descriptorForClass(cls, true);
+            ctx.descriptorForClass(cls, true, false);
         }
 
         return cls;

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
index a7f645c..3d93e70 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
@@ -82,6 +82,9 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
     /** */
     private BinaryInternalMapper mapper;
 
+    /** */
+    private boolean failIfUnregistered;
+
     /**
      * @param ctx Context.
      */
@@ -113,6 +116,13 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
     }
 
     /**
+     * @param failIfUnregistered Fail if unregistered.
+     */
+    public void failIfUnregistered(boolean failIfUnregistered) {
+        this.failIfUnregistered = failIfUnregistered;
+    }
+
+    /**
      * @param typeId Type ID.
      */
     public void typeId(int typeId) {
@@ -161,7 +171,7 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
 
         Class<?> cls = obj.getClass();
 
-        BinaryClassDescriptor desc = ctx.descriptorForClass(cls, false);
+        BinaryClassDescriptor desc = ctx.descriptorForClass(cls, false, 
failIfUnregistered);
 
         if (desc == null)
             throw new BinaryObjectException("Object is not binary: [class=" + 
cls + ']');
@@ -724,7 +734,10 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
             if (tryWriteAsHandle(val))
                 return;
 
-            BinaryClassDescriptor desc = 
ctx.descriptorForClass(val.getClass().getComponentType(), false);
+            BinaryClassDescriptor desc = ctx.descriptorForClass(
+                val.getClass().getComponentType(),
+                false,
+                failIfUnregistered);
 
             out.unsafeEnsure(1 + 4);
             out.unsafeWriteByte(GridBinaryMarshaller.OBJ_ARR);
@@ -795,7 +808,7 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
         if (val == null)
             out.writeByte(GridBinaryMarshaller.NULL);
         else {
-            BinaryClassDescriptor desc = 
ctx.descriptorForClass(val.getDeclaringClass(), false);
+            BinaryClassDescriptor desc = 
ctx.descriptorForClass(val.getDeclaringClass(), false, failIfUnregistered);
 
             out.unsafeEnsure(1 + 4);
 
@@ -848,7 +861,10 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
         if (val == null)
             out.writeByte(GridBinaryMarshaller.NULL);
         else {
-            BinaryClassDescriptor desc = 
ctx.descriptorForClass(val.getClass().getComponentType(), false);
+            BinaryClassDescriptor desc = ctx.descriptorForClass(
+                val.getClass().getComponentType(),
+                false,
+                failIfUnregistered);
 
             out.unsafeEnsure(1 + 4);
 
@@ -877,7 +893,7 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
         if (val == null)
             out.writeByte(GridBinaryMarshaller.NULL);
         else {
-            BinaryClassDescriptor desc = ctx.descriptorForClass(val, false);
+            BinaryClassDescriptor desc = ctx.descriptorForClass(val, false, 
failIfUnregistered);
 
             out.unsafeEnsure(1 + 4);
 
@@ -906,7 +922,7 @@ public class BinaryWriterExImpl implements BinaryWriter, 
BinaryRawWriterEx, Obje
             out.unsafeWriteInt(intfs.length);
 
             for (Class<?> intf : intfs) {
-                BinaryClassDescriptor desc = ctx.descriptorForClass(intf, 
false);
+                BinaryClassDescriptor desc = ctx.descriptorForClass(intf, 
false, failIfUnregistered);
 
                 if (desc.registered())
                     out.writeInt(desc.typeId());

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
index d6c8abd..7439589 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
@@ -240,14 +240,17 @@ public class GridBinaryMarshaller {
 
     /**
      * @param obj Object to marshal.
+     * @param failIfUnregistered Throw exception if class isn't registered.
      * @return Byte array.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public byte[] marshal(@Nullable Object obj) throws BinaryObjectException {
+    public byte[] marshal(@Nullable Object obj, boolean failIfUnregistered) 
throws BinaryObjectException {
         if (obj == null)
             return new byte[] { NULL };
 
         try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx)) {
+            writer.failIfUnregistered(failIfUnregistered);
+
             writer.marshal(obj);
 
             return writer.array();

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
index bc5eb9e..3930c46 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
@@ -63,7 +63,7 @@ public class BinaryBuilderEnum implements 
BinaryBuilderSerializationAware {
                 throw new BinaryInvalidTypeException("Failed to load the 
class: " + clsName, e);
             }
 
-            this.typeId = reader.binaryContext().descriptorForClass(cls, 
false).typeId();
+            this.typeId = reader.binaryContext().descriptorForClass(cls, 
false, false).typeId();
         }
         else {
             this.typeId = typeId;

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
index 42f6873..5333cc4 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
@@ -129,7 +129,7 @@ class BinaryBuilderSerializer {
             writer.context().updateMetadata(typeId, meta);
 
             // Need register class for marshaller to be able to deserialize 
enum value.
-            
writer.context().descriptorForClass(((Enum)val).getDeclaringClass(), false);
+            
writer.context().descriptorForClass(((Enum)val).getDeclaringClass(), false, 
false);
 
             writer.writeByte(GridBinaryMarshaller.ENUM);
             writer.writeInt(typeId);

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
index 787ff63..c0e79ec 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
@@ -56,7 +56,7 @@ class BinaryEnumArrayLazyValue extends 
BinaryAbstractLazyValue {
                 throw new BinaryInvalidTypeException("Failed to load the 
class: " + clsName, e);
             }
 
-            compTypeId = reader.binaryContext().descriptorForClass(cls, 
true).typeId();
+            compTypeId = reader.binaryContext().descriptorForClass(cls, true, 
false).typeId();
         }
         else {
             compTypeId = typeId;

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
index 8962107..d4882dc 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
@@ -55,7 +55,7 @@ class BinaryObjectArrayLazyValue extends 
BinaryAbstractLazyValue {
                 throw new BinaryInvalidTypeException("Failed to load the 
class: " + clsName, e);
             }
 
-            compTypeId = reader.binaryContext().descriptorForClass(cls, 
true).typeId();
+            compTypeId = reader.binaryContext().descriptorForClass(cls, true, 
false).typeId();
         }
         else {
             compTypeId = typeId;

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
index b9eb3e5..3fc5dc4 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
@@ -157,7 +157,7 @@ public class BinaryObjectBuilderImpl implements 
BinaryObjectBuilder {
                 throw new BinaryInvalidTypeException("Failed to load the 
class: " + clsNameToWrite, e);
             }
 
-            this.typeId = ctx.descriptorForClass(cls, false).typeId();
+            this.typeId = ctx.descriptorForClass(cls, false, false).typeId();
 
             registeredType = false;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientBinaryMarshaller.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientBinaryMarshaller.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientBinaryMarshaller.java
index c68b8f9..aac6873 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientBinaryMarshaller.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientBinaryMarshaller.java
@@ -66,7 +66,7 @@ class ClientBinaryMarshaller {
      * Serializes Java object into a byte array.
      */
     public byte[] marshal(Object obj) {
-        return impl.marshal(obj);
+        return impl.marshal(obj, false);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
index 4350687..385ed59 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
@@ -63,7 +63,7 @@ public class CacheDefaultBinaryAffinityKeyMapper extends 
GridCacheDefaultAffinit
     /** {@inheritDoc} */
     @Override public Object affinityKey(Object key) {
         try {
-            key = proc.toBinary(key);
+            key = proc.toBinary(key, false);
         }
         catch (IgniteException e) {
             U.error(log, "Failed to marshal key to binary: " + key, e);

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
index 99f9f97..d2b98f2 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
@@ -581,6 +581,16 @@ public class CacheGroupContext {
     }
 
     /**
+     * @return {@code True} if current thread holds lock on topology.
+     */
+    public boolean isTopologyLocked() {
+        if (top == null)
+            return false;
+
+        return top.holdsLock();
+    }
+
+    /**
      * @return Offheap manager.
      */
     public IgniteCacheOffheapManager offheap() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index c5f4d3c..191734b 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -1799,7 +1799,7 @@ public class GridCacheContext<K, V> implements 
Externalizable {
     @Nullable public CacheObject toCacheObject(@Nullable Object obj) {
         assert validObjectForCache(obj) : obj;
 
-        return cacheObjects().toCacheObject(cacheObjCtx, obj, true);
+        return cacheObjects().toCacheObject(cacheObjCtx, obj, true, 
grp.isTopologyLocked());
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
index 551d70d..bc85931 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
@@ -31,6 +31,7 @@ import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.internal.GridDirectCollection;
 import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.UnregisteredClassException;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -242,6 +243,10 @@ public class GridCacheReturn implements Externalizable, 
Message {
                 v = resMap;
             }
 
+            // This exception means that we should register class and call 
EntryProcessor again.
+            if (err != null && err instanceof UnregisteredClassException)
+                throw (UnregisteredClassException) err;
+
             CacheInvokeResult res0 = err == null ? 
CacheInvokeResult.fromResult(res) : CacheInvokeResult.fromError(err);
 
             Object resKey = key0 != null ? key0 :

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java
index 14dd5cb..c7e2e68 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessor.java
@@ -140,8 +140,9 @@ public interface CacheObjectBinaryProcessor extends 
IgniteCacheObjectProcessor {
 
     /**
      * @param obj Original object.
+     * @param failIfUnregistered Throw exception if class isn't registered.
      * @return Binary object (in case binary marshaller is used).
      * @throws IgniteException If failed.
      */
-    public Object marshalToBinary(Object obj) throws IgniteException;
+    public Object marshalToBinary(Object obj, boolean failIfUnregistered) 
throws IgniteException;
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
index 8e5ec5c..69d1f91 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
@@ -295,7 +295,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
      * @throws BinaryObjectException If failed.
      */
     public byte[] marshal(@Nullable Object obj) throws BinaryObjectException {
-        byte[] arr = binaryMarsh.marshal(obj);
+        byte[] arr = binaryMarsh.marshal(obj, false);
 
         assert arr.length > 0;
 
@@ -330,7 +330,10 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
-    @Override public Object marshalToBinary(@Nullable Object obj) throws 
BinaryObjectException {
+    @Override public Object marshalToBinary(
+        @Nullable Object obj,
+        boolean failIfUnregistered
+    ) throws BinaryObjectException {
         if (obj == null)
             return null;
 
@@ -343,7 +346,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
             Object[] pArr = new Object[arr.length];
 
             for (int i = 0; i < arr.length; i++)
-                pArr[i] = marshalToBinary(arr[i]);
+                pArr[i] = marshalToBinary(arr[i], failIfUnregistered);
 
             return pArr;
         }
@@ -352,9 +355,11 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
             IgniteBiTuple tup = (IgniteBiTuple)obj;
 
             if (obj instanceof T2)
-                return new T2<>(marshalToBinary(tup.get1()), 
marshalToBinary(tup.get2()));
+                return new T2<>(marshalToBinary(tup.get1(), 
failIfUnregistered),
+                    marshalToBinary(tup.get2(), failIfUnregistered));
 
-            return new IgniteBiTuple<>(marshalToBinary(tup.get1()), 
marshalToBinary(tup.get2()));
+            return new IgniteBiTuple<>(marshalToBinary(tup.get1(), 
failIfUnregistered),
+                marshalToBinary(tup.get2(), failIfUnregistered));
         }
 
         {
@@ -364,7 +369,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
                 Collection<?> col = (Collection<?>)obj;
 
                 for (Object item : col)
-                    pCol.add(marshalToBinary(item));
+                    pCol.add(marshalToBinary(item, failIfUnregistered));
 
                 return (pCol instanceof MutableSingletonList) ? 
U.convertToSingletonList(pCol) : pCol;
             }
@@ -377,7 +382,8 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
                 Map<?, ?> map = (Map<?, ?>)obj;
 
                 for (Map.Entry<?, ?> e : map.entrySet())
-                    pMap.put(marshalToBinary(e.getKey()), 
marshalToBinary(e.getValue()));
+                    pMap.put(marshalToBinary(e.getKey(), failIfUnregistered),
+                        marshalToBinary(e.getValue(), failIfUnregistered));
 
                 return pMap;
             }
@@ -386,13 +392,14 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
         if (obj instanceof Map.Entry) {
             Map.Entry<?, ?> e = (Map.Entry<?, ?>)obj;
 
-            return new GridMapEntry<>(marshalToBinary(e.getKey()), 
marshalToBinary(e.getValue()));
+            return new GridMapEntry<>(marshalToBinary(e.getKey(), 
failIfUnregistered),
+                marshalToBinary(e.getValue(), failIfUnregistered));
         }
 
         if (binaryMarsh.mustDeserialize(obj))
             return obj; // No need to go through marshal-unmarshal because 
result will be the same as initial object.
 
-        byte[] arr = binaryMarsh.marshal(obj);
+        byte[] arr = binaryMarsh.marshal(obj, failIfUnregistered);
 
         assert arr.length > 0;
 
@@ -765,7 +772,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
         if (!ctx.binaryEnabled() || binaryMarsh == null)
             return super.marshal(ctx, val);
 
-        byte[] arr = binaryMarsh.marshal(val);
+        byte[] arr = binaryMarsh.marshal(val, false);
 
         assert arr.length > 0;
 
@@ -801,7 +808,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
             return key;
         }
 
-        obj = toBinary(obj);
+        obj = toBinary(obj, false);
 
         if (obj instanceof BinaryObjectImpl) {
             ((BinaryObjectImpl)obj).partition(partition(ctx, cctx, obj));
@@ -814,14 +821,14 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
 
     /** {@inheritDoc} */
     @Nullable @Override public CacheObject toCacheObject(CacheObjectContext 
ctx, @Nullable Object obj,
-        boolean userObj) {
+        boolean userObj, boolean failIfUnregistered) {
         if (!ctx.binaryEnabled())
-            return super.toCacheObject(ctx, obj, userObj);
+            return super.toCacheObject(ctx, obj, userObj, failIfUnregistered);
 
         if (obj == null || obj instanceof CacheObject)
             return (CacheObject)obj;
 
-        obj = toBinary(obj);
+        obj = toBinary(obj, failIfUnregistered);
 
         if (obj instanceof CacheObject)
             return (CacheObject)obj;
@@ -864,18 +871,20 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
      * @return Binary object.
      * @throws IgniteException In case of error.
      */
-    @Nullable public Object toBinary(@Nullable Object obj) throws 
IgniteException {
+    @Nullable public Object toBinary(@Nullable Object obj, boolean 
failIfUnregistered) throws IgniteException {
         if (obj == null)
             return null;
 
         if (isBinaryObject(obj))
             return obj;
 
-        return marshalToBinary(obj);
+        return marshalToBinary(obj, failIfUnregistered);
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public IgniteNodeValidationResult 
validateNode(ClusterNode rmtNode, DiscoveryDataBag.JoiningNodeDiscoveryData 
discoData) {
+    @Nullable @Override public IgniteNodeValidationResult 
validateNode(ClusterNode rmtNode,
+        DiscoveryDataBag.JoiningNodeDiscoveryData discoData
+    ) {
         IgniteNodeValidationResult res;
 
         if (getBoolean(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK) || !(marsh 
instanceof BinaryMarshaller))

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java
index e88819b..71475be 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/IgniteBinaryImpl.java
@@ -66,7 +66,7 @@ public class IgniteBinaryImpl implements IgniteBinary {
         guard();
 
         try {
-            return (T)proc.marshalToBinary(obj);
+            return (T)proc.marshalToBinary(obj, false);
         }
         finally {
             unguard();

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridClientPartitionTopology.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridClientPartitionTopology.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridClientPartitionTopology.java
index fc80bbc..54a850c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridClientPartitionTopology.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridClientPartitionTopology.java
@@ -199,6 +199,11 @@ public class GridClientPartitionTopology implements 
GridDhtPartitionTopology {
     }
 
     /** {@inheritDoc} */
+    @Override public boolean holdsLock() {
+        return lock.isWriteLockedByCurrentThread() || lock.getReadHoldCount() 
> 0;
+    }
+
+    /** {@inheritDoc} */
     @Override public void updateTopologyVersion(
         GridDhtTopologyFuture exchFut,
         DiscoCache discoCache,

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopology.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopology.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopology.java
index b77dbd6..42ef309 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopology.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopology.java
@@ -59,6 +59,10 @@ public interface GridDhtPartitionTopology {
     public void readUnlock();
 
     /**
+     * @return {@code True} if locked by current thread.
+     */
+    public boolean holdsLock();
+    /**
      * Updates topology version.
      *
      * @param exchFut Exchange future.

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopologyImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopologyImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopologyImpl.java
index cabb0b8..ac338ae 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopologyImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtPartitionTopologyImpl.java
@@ -235,6 +235,11 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
     }
 
     /** {@inheritDoc} */
+    @Override public boolean holdsLock() {
+        return lock.isWriteLockedByCurrentThread() || lock.getReadHoldCount() 
> 0;
+    }
+
+    /** {@inheritDoc} */
     @Override public void updateTopologyVersion(
         GridDhtTopologyFuture exchFut,
         @NotNull DiscoCache discoCache,

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
index 187f1b0..8408b32 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
@@ -37,6 +37,7 @@ import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.NodeStoppingException;
+import org.apache.ignite.internal.UnregisteredClassException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.mem.IgniteOutOfMemoryException;
 import org.apache.ignite.internal.pagemem.wal.StorageException;
@@ -62,6 +63,7 @@ import 
org.apache.ignite.internal.processors.cache.GridCacheReturn;
 import org.apache.ignite.internal.processors.cache.GridCacheUpdateAtomicResult;
 import org.apache.ignite.internal.processors.cache.IgniteCacheExpiryPolicy;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import 
org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheAdapter;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheEntry;
@@ -84,6 +86,7 @@ import 
org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalEx;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import 
org.apache.ignite.internal.processors.cache.version.GridCacheVersionConflictContext;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersionEx;
+import 
org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
 import org.apache.ignite.internal.util.GridLongList;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
@@ -1707,43 +1710,56 @@ public class GridDhtAtomicCache<K, V> extends 
GridDhtCacheAdapter<K, V> {
             Collection<IgniteBiTuple<GridDhtCacheEntry, GridCacheVersion>> 
deleted = null;
 
             try {
-                GridDhtPartitionTopology top = topology();
+                while (true) {
+                    try {
+                        GridDhtPartitionTopology top = topology();
 
-                top.readLock();
+                        top.readLock();
 
-                try {
-                    if (top.stopping()) {
-                        res.addFailedKeys(req.keys(), new 
CacheStoppedException(name()));
+                        try {
+                            if (top.stopping()) {
+                                res.addFailedKeys(req.keys(), new 
CacheStoppedException(name()));
 
-                        completionCb.apply(req, res);
+                                completionCb.apply(req, res);
 
-                        return;
-                    }
+                                return;
+                            }
+
+                            boolean remap = false;
+
+                            // Do not check topology version if topology was 
locked on near node by
+                            // external transaction or explicit lock.
+                            if (!req.topologyLocked()) {
+                                // Can not wait for topology future since it 
will break
+                                // GridNearAtomicCheckUpdateRequest processing.
+                                remap = 
!top.topologyVersionFuture().exchangeDone() ||
+                                    needRemap(req.topologyVersion(), 
top.readyTopologyVersion());
+                            }
 
-                    boolean remap = false;
+                            if (!remap) {
+                                DhtAtomicUpdateResult updRes = update(node, 
locked, req, res);
 
-                    // Do not check topology version if topology was locked on 
near node by
-                    // external transaction or explicit lock.
-                    if (!req.topologyLocked()) {
-                        // Can not wait for topology future since it will break
-                        // GridNearAtomicCheckUpdateRequest processing.
-                        remap = !top.topologyVersionFuture().exchangeDone() ||
-                            needRemap(req.topologyVersion(), 
top.readyTopologyVersion());
+                                dhtFut = updRes.dhtFuture();
+                                deleted = updRes.deleted();
+                                expiry = updRes.expiryPolicy();
+                            }
+                            else
+                                // Should remap all keys.
+                                
res.remapTopologyVersion(top.lastTopologyChangeVersion());
+                        }
+                        finally {
+                            top.readUnlock();
+                        }
+
+                        break;
                     }
+                    catch (UnregisteredClassException ex) {
+                        IgniteCacheObjectProcessor cacheObjProc = 
ctx.cacheObjects();
 
-                    if (!remap) {
-                        DhtAtomicUpdateResult updRes = update(node, locked, 
req, res);
+                        assert cacheObjProc instanceof 
CacheObjectBinaryProcessorImpl;
 
-                        dhtFut = updRes.dhtFuture();
-                        deleted = updRes.deleted();
-                        expiry = updRes.expiryPolicy();
+                        
((CacheObjectBinaryProcessorImpl)cacheObjProc).binaryContext().descriptorForClass(ex.cls(),
 false, false);
                     }
-                    else
-                        // Should remap all keys.
-                        
res.remapTopologyVersion(top.lastTopologyChangeVersion());
-                }
-                finally {
-                    top.readUnlock();
                 }
             }
             catch (GridCacheEntryRemovedException e) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java
index dad6728..defb3cc 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java
@@ -154,6 +154,17 @@ public interface IgniteCacheObjectProcessor extends 
GridProcessor {
 
     /**
      * @param ctx Cache context.
+     * @param obj Object.
+     * @param userObj If {@code true} then given object is object provided by 
user and should be copied
+     *        before stored in cache.
+     * @param failIfUnregistered Throw exception if class isn't registered.
+     * @return Cache object.
+     */
+    @Nullable public CacheObject toCacheObject(CacheObjectContext ctx, 
@Nullable Object obj, boolean userObj,
+        boolean failIfUnregistered);
+
+    /**
+     * @param ctx Cache context.
      * @param type Object type.
      * @param bytes Object bytes.
      * @return Cache object.

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java
index 17be90f..7f55614 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java
@@ -225,6 +225,12 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
     @Nullable @Override public CacheObject toCacheObject(CacheObjectContext 
ctx,
         @Nullable Object obj,
         boolean userObj) {
+        return toCacheObject(ctx, obj, userObj, false);
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public CacheObject toCacheObject(CacheObjectContext 
ctx, @Nullable Object obj, boolean userObj,
+        boolean failIfUnregistered) {
         if (obj == null || obj instanceof CacheObject)
             return (CacheObject)obj;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/main/java/org/apache/ignite/internal/util/StripedCompositeReadWriteLock.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/StripedCompositeReadWriteLock.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/util/StripedCompositeReadWriteLock.java
index 18ef06c..42ec397 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/util/StripedCompositeReadWriteLock.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/StripedCompositeReadWriteLock.java
@@ -63,8 +63,10 @@ public class StripedCompositeReadWriteLock implements 
ReadWriteLock {
         writeLock = new WriteLock();
     }
 
-    /** {@inheritDoc} */
-    @NotNull @Override public Lock readLock() {
+    /**
+     * @return Index of current thread stripe.
+     */
+    private int curIdx() {
         int idx;
 
         Thread curThread = Thread.currentThread();
@@ -83,7 +85,12 @@ public class StripedCompositeReadWriteLock implements 
ReadWriteLock {
         else
             idx = IDX.get();
 
-        return locks[idx % locks.length].readLock();
+        return idx % locks.length;
+    }
+
+    /** {@inheritDoc} */
+    @NotNull @Override public Lock readLock() {
+        return locks[curIdx()].readLock();
     }
 
     /** {@inheritDoc} */
@@ -102,6 +109,18 @@ public class StripedCompositeReadWriteLock implements 
ReadWriteLock {
     }
 
     /**
+     * Queries the number of reentrant read holds on this lock by the
+     * current thread.  A reader thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the read lock by the current thread,
+     *         or zero if the read lock is not held by the current thread
+     */
+    public int getReadHoldCount() {
+        return locks[curIdx()].getReadHoldCount();
+    }
+
+    /**
      * Read lock.
      */
     @SuppressWarnings("unused")

http://git-wip-us.apache.org/repos/asf/ignite/blob/929a12d4/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheEntryProcessorCallTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheEntryProcessorCallTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheEntryProcessorCallTest.java
index 2f80462..4efe513 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheEntryProcessorCallTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheEntryProcessorCallTest.java
@@ -154,6 +154,11 @@ public class IgniteCacheEntryProcessorCallTest extends 
GridCommonAbstractTest {
 
         int key = 0;
 
+        // Call EntryProcessor on every node to ensure that binary metadata 
has been registered everywhere.
+        for (int i = 0; i < 1_000; i++)
+            ignite(i % SRV_CNT).<Integer, TestValue>cache(ccfg.getName())
+                .invoke(key++, new TestEntryProcessor(OP_UPDATE), new 
TestValue(Integer.MIN_VALUE));
+
         checkEntryProcessCall(key++, clientCache1, null, null, expCallCnt);
 
         if (ccfg.getAtomicityMode() == TRANSACTIONAL) {

Reply via email to