You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/11/20 07:28:56 UTC

[1/5] ignite git commit: IGNITE-1917: Binary protocol performance optimizations.

Repository: ignite
Updated Branches:
  refs/heads/ignite-1282 5ea0625b4 -> 4a1af37e3


http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformBigEndianOutputStreamImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformBigEndianOutputStreamImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformBigEndianOutputStreamImpl.java
index e5fd71b..2f6ad5c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformBigEndianOutputStreamImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformBigEndianOutputStreamImpl.java
@@ -163,4 +163,34 @@ public class PlatformBigEndianOutputStreamImpl extends PlatformOutputStreamImpl
 
         shift(cnt);
     }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(short val) {
+        super.unsafeWriteShort(Short.reverseBytes(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(int pos, short val) {
+        super.unsafeWriteShort(pos, Short.reverseBytes(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteChar(char val) {
+        super.unsafeWriteChar(Character.reverseBytes(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int val) {
+        super.unsafeWriteInt(Integer.reverseBytes(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int pos, int val) {
+        super.unsafeWriteInt(pos, Integer.reverseBytes(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteLong(long val) {
+        super.unsafeWriteLong(Long.reverseBytes(val));
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformOutputStreamImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformOutputStreamImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformOutputStreamImpl.java
index 16b1567..670dd28 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformOutputStreamImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/memory/PlatformOutputStreamImpl.java
@@ -223,6 +223,69 @@ public class PlatformOutputStreamImpl implements PlatformOutputStream {
     }
 
     /** {@inheritDoc} */
+    @Override public void unsafeEnsure(int cap) {
+        ensureCapacity(pos + cap);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteByte(byte val) {
+        UNSAFE.putByte(data + pos++, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteBoolean(boolean val) {
+        unsafeWriteByte(val ? (byte) 1 : (byte) 0);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(short val) {
+        UNSAFE.putShort(data + pos, val);
+
+        shift(2);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(int pos, short val) {
+        UNSAFE.putShort(data + pos, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteChar(char val) {
+        UNSAFE.putChar(data + pos, val);
+
+        shift(2);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int val) {
+        UNSAFE.putInt(data + pos, val);
+
+        shift(4);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int pos, int val) {
+        UNSAFE.putInt(data + pos, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteLong(long val) {
+        UNSAFE.putLong(data + pos, val);
+
+        shift(8);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteFloat(float val) {
+        unsafeWriteInt(Float.floatToIntBits(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteDouble(double val) {
+        unsafeWriteLong(Double.doubleToLongBits(val));
+    }
+
+    /** {@inheritDoc} */
     @Override public void synchronize() {
         PlatformMemoryUtils.length(mem.pointer(), pos);
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/util/GridEnumCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridEnumCache.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridEnumCache.java
deleted file mode 100644
index f84c1e5..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridEnumCache.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.util;
-
-import java.util.concurrent.ConcurrentMap;
-import org.jsr166.ConcurrentHashMap8;
-
-/**
- * Cache for enum constants.
- */
-public class GridEnumCache {
-    /** Cache for enum constants. */
-    private static final ConcurrentMap<Class<?>, Object[]> ENUM_CACHE = new ConcurrentHashMap8<>();
-
-    /**
-     * Gets enum constants for provided class.
-     *
-     * @param cls Class.
-     * @return Enum constants.
-     */
-    public static Object[] get(Class<?> cls) {
-        assert cls != null;
-
-        Object[] vals = ENUM_CACHE.get(cls);
-
-        if (vals == null) {
-            vals = cls.getEnumConstants();
-
-            ENUM_CACHE.putIfAbsent(cls, vals);
-        }
-
-        return vals;
-    }
-
-    /**
-     * Clears cache.
-     */
-    public static void clear() {
-        ENUM_CACHE.clear();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
index 9809a7e..17ec7d6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
@@ -68,7 +68,7 @@ import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 
-import static org.apache.ignite.internal.portable.PortableThreadLocalMemoryAllocator.THREAD_LOCAL_ALLOC;
+import static org.apache.ignite.internal.portable.streams.PortableMemoryAllocator.INSTANCE;
 import static org.junit.Assert.assertArrayEquals;
 
 /**
@@ -93,7 +93,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
      * @throws Exception If failed.
      */
     public void testByte() throws Exception {
-        assertEquals((byte)100, marshalUnmarshal((byte)100).byteValue());
+        assertEquals((byte) 100, marshalUnmarshal((byte) 100).byteValue());
     }
 
     /**
@@ -1492,11 +1492,11 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
 
         BinaryObject copy = copy(po, F.<String, Object>asMap("bArr", new byte[]{1, 2, 3}));
 
-        assertArrayEquals(new byte[] {1, 2, 3}, copy.<byte[]>field("bArr"));
+        assertArrayEquals(new byte[]{1, 2, 3}, copy.<byte[]>field("bArr"));
 
         SimpleObject obj0 = copy.deserialize();
 
-        assertArrayEquals(new byte[] {1, 2, 3}, obj0.bArr);
+        assertArrayEquals(new byte[]{1, 2, 3}, obj0.bArr);
     }
 
     /**
@@ -1741,7 +1741,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
 
         assertEquals("str555", obj0.str);
         assertEquals(newObj, obj0.inner);
-        assertArrayEquals(new byte[] {6, 7, 9}, obj0.bArr);
+        assertArrayEquals(new byte[]{6, 7, 9}, obj0.bArr);
     }
 
     /**
@@ -1769,7 +1769,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
         map.put("inner", newObj);
         map.put("s", (short)2323);
         map.put("bArr", new byte[]{6, 7, 9});
-        map.put("b", (byte)111);
+        map.put("b", (byte) 111);
 
         BinaryObject copy = copy(po, map);
 
@@ -1786,8 +1786,8 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
         assertEquals("str555", obj0.str);
         assertEquals(newObj, obj0.inner);
         assertEquals((short)2323, obj0.s);
-        assertArrayEquals(new byte[] {6, 7, 9}, obj0.bArr);
-        assertEquals((byte)111, obj0.b);
+        assertArrayEquals(new byte[]{6, 7, 9}, obj0.bArr);
+        assertEquals((byte) 111, obj0.b);
     }
 
     /**
@@ -2069,28 +2069,28 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
      */
     public void testThreadLocalArrayReleased() throws Exception {
         // Checking the writer directly.
-        assertEquals(false, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+        assertEquals(false, INSTANCE.isAcquired());
 
         PortableMarshaller marsh0 = createMarshaller();
-
+        
         try (BinaryWriterExImpl writer = new BinaryWriterExImpl(portableContext(marsh0))) {
-            assertEquals(true, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+            assertEquals(true, INSTANCE.isAcquired());
 
             writer.writeString("Thread local test");
 
             writer.array();
 
-            assertEquals(true, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+            assertEquals(true, INSTANCE.isAcquired());
         }
 
         // Checking the portable marshaller.
-        assertEquals(false, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+        assertEquals(false, INSTANCE.isAcquired());
 
         PortableMarshaller marsh = createMarshaller();
 
         marsh.marshal(new SimpleObject());
 
-        assertEquals(false, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+        assertEquals(false, INSTANCE.isAcquired());
 
         // Checking the builder.
         PortableMarshaller marsh2 = createMarshaller();
@@ -2102,7 +2102,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
 
         BinaryObject portableObj = builder.build();
 
-        assertEquals(false, THREAD_LOCAL_ALLOC.isThreadLocalArrayAcquired());
+        assertEquals(false, INSTANCE.isAcquired());
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index 3e41979..bee9990 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -61,7 +61,7 @@ import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.IgnitionEx;
 import org.apache.ignite.internal.processors.resource.GridSpringResourceContext;
 import org.apache.ignite.internal.util.GridClassLoaderCache;
-import org.apache.ignite.internal.util.GridEnumCache;
+import org.apache.ignite.internal.portable.BinaryEnumCache;
 import org.apache.ignite.internal.util.GridTestClockTimer;
 import org.apache.ignite.internal.util.GridUnsafe;
 import org.apache.ignite.internal.util.typedef.F;
@@ -1365,7 +1365,7 @@ public abstract class GridAbstractTest extends TestCase {
                 GridClassLoaderCache.clear();
                 U.clearClassCache();
                 MarshallerExclusions.clearCache();
-                GridEnumCache.clear();
+                BinaryEnumCache.clear();
             }
 
             Thread.currentThread().setContextClassLoader(clsLdr);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
index 411ef05..08a98f6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
@@ -565,7 +565,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         /// Check scan query with partitions.
         /// </summary>
         [Test]
-        [Ignore("IGNITE-1012")]
         public void TestScanQueryPartitions([Values(true, false)]  bool loc)
         {
             CheckScanQueryPartitions<QueryPerson>(MaxItemCnt, loc, false);
@@ -575,7 +574,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         /// Check scan query with partitions in binary mode.
         /// </summary>
         [Test]
-        [Ignore("IGNITE-1012")]
         public void TestScanQueryPartitionsBinary([Values(true, false)]  bool loc)
         {
             CheckScanQueryPartitions<BinaryObject>(MaxItemCnt, loc, true);


[2/5] ignite git commit: IGNITE-1917: Binary protocol performance optimizations.

Posted by vo...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
index 8543ce6..3edf980 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
@@ -69,7 +69,7 @@ public class PortableClassDescriptor {
     private final BinaryIdMapper idMapper;
 
     /** */
-    private final Mode mode;
+    private final BinaryWriteMode mode;
 
     /** */
     private final boolean userType;
@@ -87,7 +87,7 @@ public class PortableClassDescriptor {
     private final Constructor<?> ctor;
 
     /** */
-    private final Collection<FieldInfo> fields;
+    private final BinaryFieldAccessor[] fields;
 
     /** */
     private final Method writeReplaceMtd;
@@ -99,7 +99,7 @@ public class PortableClassDescriptor {
     private final Map<String, Integer> stableFieldsMeta;
 
     /** Object schemas. Initialized only for serializable classes and contains only 1 entry. */
-    private final Collection<PortableSchema> stableSchemas;
+    private final PortableSchema stableSchema;
 
     /** Schema registry. */
     private final PortableSchemaRegistry schemaReg;
@@ -167,9 +167,9 @@ public class PortableClassDescriptor {
         useOptMarshaller = !predefined && initUseOptimizedMarshallerFlag();
 
         if (excluded)
-            mode = Mode.EXCLUSION;
+            mode = BinaryWriteMode.EXCLUSION;
         else
-            mode = serializer != null ? Mode.PORTABLE : mode(cls);
+            mode = serializer != null ? BinaryWriteMode.PORTABLE : PortableUtils.mode(cls);
 
         switch (mode) {
             case BYTE:
@@ -210,7 +210,7 @@ public class PortableClassDescriptor {
                 ctor = null;
                 fields = null;
                 stableFieldsMeta = null;
-                stableSchemas = null;
+                stableSchema = null;
 
                 break;
 
@@ -219,13 +219,13 @@ public class PortableClassDescriptor {
                 ctor = constructor(cls);
                 fields = null;
                 stableFieldsMeta = null;
-                stableSchemas = null;
+                stableSchema = null;
 
                 break;
 
             case OBJECT:
                 ctor = constructor(cls);
-                fields = new ArrayList<>();
+                ArrayList<BinaryFieldAccessor> fields0 = new ArrayList<>();
                 stableFieldsMeta = metaDataEnabled ? new HashMap<String, Integer>() : null;
 
                 PortableSchema.Builder schemaBuilder = PortableSchema.Builder.newBuilder();
@@ -250,20 +250,22 @@ public class PortableClassDescriptor {
                             if (!ids.add(fieldId))
                                 throw new BinaryObjectException("Duplicate field ID: " + name);
 
-                            FieldInfo fieldInfo = new FieldInfo(f, fieldId);
+                            BinaryFieldAccessor fieldInfo = BinaryFieldAccessor.create(f, fieldId);
 
-                            fields.add(fieldInfo);
+                            fields0.add(fieldInfo);
 
                             schemaBuilder.addField(fieldId);
 
                             if (metaDataEnabled)
-                                stableFieldsMeta.put(name, fieldInfo.fieldMode().typeId());
+                                stableFieldsMeta.put(name, fieldInfo.mode().typeId());
                         }
                     }
                 }
-
-                stableSchemas = Collections.singleton(schemaBuilder.build());
-
+                
+                fields = fields0.toArray(new BinaryFieldAccessor[fields0.size()]);
+                
+                stableSchema = schemaBuilder.build();
+                
                 break;
 
             default:
@@ -271,7 +273,8 @@ public class PortableClassDescriptor {
                 throw new BinaryObjectException("Invalid mode: " + mode);
         }
 
-        if (mode == Mode.PORTABLE || mode == Mode.EXTERNALIZABLE || mode == Mode.OBJECT) {
+        if (mode == BinaryWriteMode.PORTABLE || mode == BinaryWriteMode.EXTERNALIZABLE ||
+            mode == BinaryWriteMode.OBJECT) {
             readResolveMtd = U.findNonPublicMethod(cls, "readResolve");
             writeReplaceMtd = U.findNonPublicMethod(cls, "writeReplace");
         }
@@ -310,10 +313,10 @@ public class PortableClassDescriptor {
     }
 
     /**
-     * @return Schemas.
+     * @return Schema.
      */
-    Collection<PortableSchema> schemas() {
-        return stableSchemas;
+    PortableSchema schema() {
+        return stableSchema;
     }
 
     /**
@@ -380,52 +383,46 @@ public class PortableClassDescriptor {
         assert obj != null;
         assert writer != null;
 
+        writer.typeId(typeId);
+
         switch (mode) {
             case BYTE:
-                writer.doWriteByte(GridPortableMarshaller.BYTE);
-                writer.doWriteByte((byte)obj);
+                writer.writeByteFieldPrimitive((byte) obj);
 
                 break;
 
             case SHORT:
-                writer.doWriteByte(GridPortableMarshaller.SHORT);
-                writer.doWriteShort((short)obj);
+                writer.writeShortFieldPrimitive((short)obj);
 
                 break;
 
             case INT:
-                writer.doWriteByte(GridPortableMarshaller.INT);
-                writer.doWriteInt((int)obj);
+                writer.writeIntFieldPrimitive((int) obj);
 
                 break;
 
             case LONG:
-                writer.doWriteByte(GridPortableMarshaller.LONG);
-                writer.doWriteLong((long)obj);
+                writer.writeLongFieldPrimitive((long) obj);
 
                 break;
 
             case FLOAT:
-                writer.doWriteByte(GridPortableMarshaller.FLOAT);
-                writer.doWriteFloat((float)obj);
+                writer.writeFloatFieldPrimitive((float) obj);
 
                 break;
 
             case DOUBLE:
-                writer.doWriteByte(GridPortableMarshaller.DOUBLE);
-                writer.doWriteDouble((double)obj);
+                writer.writeDoubleFieldPrimitive((double) obj);
 
                 break;
 
             case CHAR:
-                writer.doWriteByte(GridPortableMarshaller.CHAR);
-                writer.doWriteChar((char)obj);
+                writer.writeCharFieldPrimitive((char) obj);
 
                 break;
 
             case BOOLEAN:
-                writer.doWriteByte(GridPortableMarshaller.BOOLEAN);
-                writer.doWriteBoolean((boolean)obj);
+                writer.writeBooleanFieldPrimitive((boolean) obj);
 
                 break;
 
@@ -623,9 +620,11 @@ public class PortableClassDescriptor {
             case OBJECT:
                 if (writeHeader(obj, writer)) {
                     try {
-                        for (FieldInfo info : fields)
+                        for (BinaryFieldAccessor info : fields)
                             info.write(obj, writer);
 
+                        writer.schemaId(stableSchema.schemaId());
+
                         writer.postWrite(userType);
                     }
                     finally {
@@ -683,7 +682,7 @@ public class PortableClassDescriptor {
 
                 reader.setHandler(res);
 
-                for (FieldInfo info : fields)
+                for (BinaryFieldAccessor info : fields)
                     info.read(res, reader);
 
                 break;
@@ -723,12 +722,22 @@ public class PortableClassDescriptor {
         if (writer.tryWriteAsHandle(obj))
             return false;
 
-        PortableUtils.writeHeader(
-            writer,
-            registered ? typeId : GridPortableMarshaller.UNREGISTERED_TYPE_ID,
-            obj instanceof CacheObjectImpl ? 0 : obj.hashCode(),
-            registered ? null : cls.getName()
-        );
+        if (registered) {
+            PortableUtils.writeHeader(
+                writer,
+                typeId,
+                obj instanceof CacheObjectImpl ? 0 : obj.hashCode(),
+                null
+            );
+        }
+        else {
+            PortableUtils.writeHeader(
+                writer,
+                GridPortableMarshaller.UNREGISTERED_TYPE_ID,
+                obj instanceof CacheObjectImpl ? 0 : obj.hashCode(),
+                cls.getName()
+            );
+        }
 
         return true;
     }
@@ -794,658 +803,4 @@ public class PortableClassDescriptor {
 
         return use;
     }
-
-    /**
-     * @param cls Class.
-     * @return Mode.
-     */
-    @SuppressWarnings("IfMayBeConditional")
-    private static Mode mode(Class<?> cls) {
-        assert cls != null;
-
-        if (cls == byte.class || cls == Byte.class)
-            return Mode.BYTE;
-        else if (cls == short.class || cls == Short.class)
-            return Mode.SHORT;
-        else if (cls == int.class || cls == Integer.class)
-            return Mode.INT;
-        else if (cls == long.class || cls == Long.class)
-            return Mode.LONG;
-        else if (cls == float.class || cls == Float.class)
-            return Mode.FLOAT;
-        else if (cls == double.class || cls == Double.class)
-            return Mode.DOUBLE;
-        else if (cls == char.class || cls == Character.class)
-            return Mode.CHAR;
-        else if (cls == boolean.class || cls == Boolean.class)
-            return Mode.BOOLEAN;
-        else if (cls == BigDecimal.class)
-            return Mode.DECIMAL;
-        else if (cls == String.class)
-            return Mode.STRING;
-        else if (cls == UUID.class)
-            return Mode.UUID;
-        else if (cls == Date.class)
-            return Mode.DATE;
-        else if (cls == Timestamp.class)
-            return Mode.TIMESTAMP;
-        else if (cls == byte[].class)
-            return Mode.BYTE_ARR;
-        else if (cls == short[].class)
-            return Mode.SHORT_ARR;
-        else if (cls == int[].class)
-            return Mode.INT_ARR;
-        else if (cls == long[].class)
-            return Mode.LONG_ARR;
-        else if (cls == float[].class)
-            return Mode.FLOAT_ARR;
-        else if (cls == double[].class)
-            return Mode.DOUBLE_ARR;
-        else if (cls == char[].class)
-            return Mode.CHAR_ARR;
-        else if (cls == boolean[].class)
-            return Mode.BOOLEAN_ARR;
-        else if (cls == BigDecimal[].class)
-            return Mode.DECIMAL_ARR;
-        else if (cls == String[].class)
-            return Mode.STRING_ARR;
-        else if (cls == UUID[].class)
-            return Mode.UUID_ARR;
-        else if (cls == Date[].class)
-            return Mode.DATE_ARR;
-        else if (cls == Timestamp[].class)
-            return Mode.TIMESTAMP_ARR;
-        else if (cls.isArray())
-            return cls.getComponentType().isEnum() ? Mode.ENUM_ARR : Mode.OBJECT_ARR;
-        else if (cls == BinaryObjectImpl.class)
-            return Mode.PORTABLE_OBJ;
-        else if (Binarylizable.class.isAssignableFrom(cls))
-            return Mode.PORTABLE;
-        else if (Externalizable.class.isAssignableFrom(cls))
-            return Mode.EXTERNALIZABLE;
-        else if (Map.Entry.class.isAssignableFrom(cls))
-            return Mode.MAP_ENTRY;
-        else if (Collection.class.isAssignableFrom(cls))
-            return Mode.COL;
-        else if (Map.class.isAssignableFrom(cls))
-            return Mode.MAP;
-        else if (cls == BinaryObjectImpl.class)
-            return Mode.PORTABLE_OBJ;
-        else if (cls.isEnum())
-            return Mode.ENUM;
-        else if (cls == Class.class)
-            return Mode.CLASS;
-        else
-            return Mode.OBJECT;
-    }
-
-    /** */
-    private static class FieldInfo {
-        /** */
-        private final Field field;
-
-        /** */
-        private final int id;
-
-        /** */
-        private final Mode mode;
-
-        /**
-         * @param field Field.
-         * @param id Field ID.
-         */
-        private FieldInfo(Field field, int id) {
-            assert field != null;
-
-            this.field = field;
-            this.id = id;
-
-            Class<?> type = field.getType();
-
-            mode = mode(type);
-        }
-
-        /**
-         * @return Field mode.
-         */
-        public Mode fieldMode() {
-            return mode;
-        }
-
-        /**
-         * @param obj Object.
-         * @param writer Writer.
-         * @throws BinaryObjectException In case of error.
-         */
-        public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
-            assert obj != null;
-            assert writer != null;
-
-            writer.writeFieldId(id);
-
-            Object val;
-
-            try {
-                val = field.get(obj);
-            }
-            catch (IllegalAccessException e) {
-                throw new BinaryObjectException("Failed to get value for field: " + field, e);
-            }
-
-            switch (mode) {
-                case BYTE:
-                    writer.writeByteField((Byte)val);
-
-                    break;
-
-                case SHORT:
-                    writer.writeShortField((Short)val);
-
-                    break;
-
-                case INT:
-                    writer.writeIntField((Integer)val);
-
-                    break;
-
-                case LONG:
-                    writer.writeLongField((Long)val);
-
-                    break;
-
-                case FLOAT:
-                    writer.writeFloatField((Float)val);
-
-                    break;
-
-                case DOUBLE:
-                    writer.writeDoubleField((Double)val);
-
-                    break;
-
-                case CHAR:
-                    writer.writeCharField((Character)val);
-
-                    break;
-
-                case BOOLEAN:
-                    writer.writeBooleanField((Boolean)val);
-
-                    break;
-
-                case DECIMAL:
-                    writer.writeDecimalField((BigDecimal)val);
-
-                    break;
-
-                case STRING:
-                    writer.writeStringField((String)val);
-
-                    break;
-
-                case UUID:
-                    writer.writeUuidField((UUID)val);
-
-                    break;
-
-                case DATE:
-                    writer.writeDateField((Date)val);
-
-                    break;
-
-                case TIMESTAMP:
-                    writer.writeTimestampField((Timestamp)val);
-
-                    break;
-
-                case BYTE_ARR:
-                    writer.writeByteArrayField((byte[])val);
-
-                    break;
-
-                case SHORT_ARR:
-                    writer.writeShortArrayField((short[]) val);
-
-                    break;
-
-                case INT_ARR:
-                    writer.writeIntArrayField((int[]) val);
-
-                    break;
-
-                case LONG_ARR:
-                    writer.writeLongArrayField((long[]) val);
-
-                    break;
-
-                case FLOAT_ARR:
-                    writer.writeFloatArrayField((float[]) val);
-
-                    break;
-
-                case DOUBLE_ARR:
-                    writer.writeDoubleArrayField((double[]) val);
-
-                    break;
-
-                case CHAR_ARR:
-                    writer.writeCharArrayField((char[]) val);
-
-                    break;
-
-                case BOOLEAN_ARR:
-                    writer.writeBooleanArrayField((boolean[]) val);
-
-                    break;
-
-                case DECIMAL_ARR:
-                    writer.writeDecimalArrayField((BigDecimal[]) val);
-
-                    break;
-
-                case STRING_ARR:
-                    writer.writeStringArrayField((String[]) val);
-
-                    break;
-
-                case UUID_ARR:
-                    writer.writeUuidArrayField((UUID[]) val);
-
-                    break;
-
-                case DATE_ARR:
-                    writer.writeDateArrayField((Date[]) val);
-
-                    break;
-
-                case TIMESTAMP_ARR:
-                    writer.writeTimestampArrayField((Timestamp[]) val);
-
-                    break;
-
-                case OBJECT_ARR:
-                    writer.writeObjectArrayField((Object[])val);
-
-                    break;
-
-                case COL:
-                    writer.writeCollectionField((Collection<?>)val);
-
-                    break;
-
-                case MAP:
-                    writer.writeMapField((Map<?, ?>)val);
-
-                    break;
-
-                case MAP_ENTRY:
-                    writer.writeMapEntryField((Map.Entry<?, ?>)val);
-
-                    break;
-
-                case PORTABLE_OBJ:
-                    writer.writePortableObjectField((BinaryObjectImpl)val);
-
-                    break;
-
-                case ENUM:
-                    writer.writeEnumField((Enum<?>)val);
-
-                    break;
-
-                case ENUM_ARR:
-                    writer.writeEnumArrayField((Object[])val);
-
-                    break;
-
-                case PORTABLE:
-                case EXTERNALIZABLE:
-                case OBJECT:
-                    writer.writeObjectField(val);
-
-                    break;
-
-                case CLASS:
-                    writer.writeClassField((Class)val);
-
-                    break;
-
-                default:
-                    assert false : "Invalid mode: " + mode;
-            }
-        }
-
-        /**
-         * @param obj Object.
-         * @param reader Reader.
-         * @throws BinaryObjectException In case of error.
-         */
-        public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
-            Object val = null;
-
-            switch (mode) {
-                case BYTE:
-                    val = reader.readByte(id);
-
-                    break;
-
-                case SHORT:
-                    val = reader.readShort(id);
-
-                    break;
-
-                case INT:
-                    val = reader.readInt(id);
-
-                    break;
-
-                case LONG:
-                    val = reader.readLong(id);
-
-                    break;
-
-                case FLOAT:
-                    val = reader.readFloat(id);
-
-                    break;
-
-                case DOUBLE:
-                    val = reader.readDouble(id);
-
-                    break;
-
-                case CHAR:
-                    val = reader.readChar(id);
-
-                    break;
-
-                case BOOLEAN:
-                    val = reader.readBoolean(id);
-
-                    break;
-
-                case DECIMAL:
-                    val = reader.readDecimal(id);
-
-                    break;
-
-                case STRING:
-                    val = reader.readString(id);
-
-                    break;
-
-                case UUID:
-                    val = reader.readUuid(id);
-
-                    break;
-
-                case DATE:
-                    val = reader.readDate(id);
-
-                    break;
-
-                case TIMESTAMP:
-                    val = reader.readTimestamp(id);
-
-                    break;
-
-                case BYTE_ARR:
-                    val = reader.readByteArray(id);
-
-                    break;
-
-                case SHORT_ARR:
-                    val = reader.readShortArray(id);
-
-                    break;
-
-                case INT_ARR:
-                    val = reader.readIntArray(id);
-
-                    break;
-
-                case LONG_ARR:
-                    val = reader.readLongArray(id);
-
-                    break;
-
-                case FLOAT_ARR:
-                    val = reader.readFloatArray(id);
-
-                    break;
-
-                case DOUBLE_ARR:
-                    val = reader.readDoubleArray(id);
-
-                    break;
-
-                case CHAR_ARR:
-                    val = reader.readCharArray(id);
-
-                    break;
-
-                case BOOLEAN_ARR:
-                    val = reader.readBooleanArray(id);
-
-                    break;
-
-                case DECIMAL_ARR:
-                    val = reader.readDecimalArray(id);
-
-                    break;
-
-                case STRING_ARR:
-                    val = reader.readStringArray(id);
-
-                    break;
-
-                case UUID_ARR:
-                    val = reader.readUuidArray(id);
-
-                    break;
-
-                case DATE_ARR:
-                    val = reader.readDateArray(id);
-
-                    break;
-
-                case TIMESTAMP_ARR:
-                    val = reader.readTimestampArray(id);
-
-                    break;
-
-                case OBJECT_ARR:
-                    val = reader.readObjectArray(id);
-
-                    break;
-
-                case COL:
-                    val = reader.readCollection(id, null);
-
-                    break;
-
-                case MAP:
-                    val = reader.readMap(id, null);
-
-                    break;
-
-                case MAP_ENTRY:
-                    val = reader.readMapEntry(id);
-
-                    break;
-
-                case PORTABLE_OBJ:
-                    val = reader.readPortableObject(id);
-
-                    break;
-
-                case ENUM:
-                    val = reader.readEnum(id, field.getType());
-
-                    break;
-
-                case ENUM_ARR:
-                    val = reader.readEnumArray(id, field.getType().getComponentType());
-
-                    break;
-
-                case PORTABLE:
-                case EXTERNALIZABLE:
-                case OBJECT:
-                    val = reader.readObject(id);
-
-                    break;
-
-                case CLASS:
-                    val = reader.readClass(id);
-
-                    break;
-
-                default:
-                    assert false : "Invalid mode: " + mode;
-            }
-
-            try {
-                if (val != null || !field.getType().isPrimitive())
-                    field.set(obj, val);
-            }
-            catch (IllegalAccessException e) {
-                throw new BinaryObjectException("Failed to set value for field: " + field, e);
-            }
-        }
-    }
-
-    /** */
-    enum Mode {
-        /** */
-        BYTE(GridPortableMarshaller.BYTE),
-
-        /** */
-        SHORT(GridPortableMarshaller.SHORT),
-
-        /** */
-        INT(GridPortableMarshaller.INT),
-
-        /** */
-        LONG(GridPortableMarshaller.LONG),
-
-        /** */
-        FLOAT(GridPortableMarshaller.FLOAT),
-
-        /** */
-        DOUBLE(GridPortableMarshaller.DOUBLE),
-
-        /** */
-        CHAR(GridPortableMarshaller.CHAR),
-
-        /** */
-        BOOLEAN(GridPortableMarshaller.BOOLEAN),
-
-        /** */
-        DECIMAL(GridPortableMarshaller.DECIMAL),
-
-        /** */
-        STRING(GridPortableMarshaller.STRING),
-
-        /** */
-        UUID(GridPortableMarshaller.UUID),
-
-        /** */
-        DATE(GridPortableMarshaller.DATE),
-
-        /** */
-        TIMESTAMP(GridPortableMarshaller.TIMESTAMP),
-
-        /** */
-        BYTE_ARR(GridPortableMarshaller.BYTE_ARR),
-
-        /** */
-        SHORT_ARR(GridPortableMarshaller.SHORT_ARR),
-
-        /** */
-        INT_ARR(GridPortableMarshaller.INT_ARR),
-
-        /** */
-        LONG_ARR(GridPortableMarshaller.LONG_ARR),
-
-        /** */
-        FLOAT_ARR(GridPortableMarshaller.FLOAT_ARR),
-
-        /** */
-        DOUBLE_ARR(GridPortableMarshaller.DOUBLE_ARR),
-
-        /** */
-        CHAR_ARR(GridPortableMarshaller.CHAR_ARR),
-
-        /** */
-        BOOLEAN_ARR(GridPortableMarshaller.BOOLEAN_ARR),
-
-        /** */
-        DECIMAL_ARR(GridPortableMarshaller.DECIMAL_ARR),
-
-        /** */
-        STRING_ARR(GridPortableMarshaller.STRING_ARR),
-
-        /** */
-        UUID_ARR(GridPortableMarshaller.UUID_ARR),
-
-        /** */
-        DATE_ARR(GridPortableMarshaller.DATE_ARR),
-
-        /** */
-        TIMESTAMP_ARR(GridPortableMarshaller.TIMESTAMP_ARR),
-
-        /** */
-        OBJECT_ARR(GridPortableMarshaller.OBJ_ARR),
-
-        /** */
-        COL(GridPortableMarshaller.COL),
-
-        /** */
-        MAP(GridPortableMarshaller.MAP),
-
-        /** */
-        MAP_ENTRY(GridPortableMarshaller.MAP_ENTRY),
-
-        /** */
-        PORTABLE_OBJ(GridPortableMarshaller.OBJ),
-
-        /** */
-        ENUM(GridPortableMarshaller.ENUM),
-
-        /** */
-        ENUM_ARR(GridPortableMarshaller.ENUM_ARR),
-
-        /** */
-        CLASS(GridPortableMarshaller.CLASS),
-
-        /** */
-        PORTABLE(GridPortableMarshaller.PORTABLE_OBJ),
-
-        /** */
-        EXTERNALIZABLE(GridPortableMarshaller.OBJ),
-
-        /** */
-        OBJECT(GridPortableMarshaller.OBJ),
-
-        /** */
-        EXCLUSION(GridPortableMarshaller.OBJ);
-
-        /** */
-        private final int typeId;
-
-        /**
-         * @param typeId Type ID.
-         */
-        Mode(int typeId) {
-            this.typeId = typeId;
-        }
-
-        /**
-         * @return Type ID.
-         */
-        int typeId() {
-            return typeId;
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
index afc23e1..e3caba4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
@@ -31,6 +31,7 @@ import java.net.URLClassLoader;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -573,8 +574,9 @@ public class PortableContext implements Externalizable {
 
         mappers.putIfAbsent(typeId, idMapper);
 
-        metaHnd.addMeta(typeId,
-            new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), null, desc.schemas()).wrap(this));
+        Collection<PortableSchema> schemas = desc.schema() != null ? Collections.singleton(desc.schema()) : null;
+
+        metaHnd.addMeta(typeId, new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), null, schemas).wrap(this));
 
         return desc;
     }
@@ -782,7 +784,7 @@ public class PortableContext implements Externalizable {
             );
 
             fieldsMeta = desc.fieldsMeta();
-            schemas = desc.schemas();
+            schemas = desc.schema() != null ? Collections.singleton(desc.schema()) : null;
 
             if (IgniteUtils.detectClassLoader(cls).equals(dfltLdr))
                 userTypes.put(id, desc);

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
deleted file mode 100644
index 869f81d..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.portable;
-
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.binary.BinaryObject;
-import org.apache.ignite.lang.IgniteBiTuple;
-import org.jetbrains.annotations.Nullable;
-
-/**
-* Reader context.
-*/
-class PortableReaderContext {
-    /** */
-    private Object oHandles;
-
-    /** */
-    private Map<Integer, BinaryObject> poHandles;
-
-    /**
-     * @param handle Handle.
-     * @param obj Object.
-     */
-    @SuppressWarnings("unchecked")
-    void setObjectHandler(int handle, Object obj) {
-        assert obj != null;
-
-        if (oHandles == null)
-            oHandles = new IgniteBiTuple(handle, obj);
-        else if (oHandles instanceof IgniteBiTuple) {
-            Map map = new HashMap(3, 1.0f);
-
-            IgniteBiTuple t = (IgniteBiTuple)oHandles;
-
-            map.put(t.getKey(), t.getValue());
-            map.put(handle, obj);
-
-            oHandles = map;
-        }
-        else
-            ((Map)oHandles).put(handle, obj);
-    }
-
-    /**
-     * @param handle Handle.
-     * @param po Portable object.
-     */
-    void setPortableHandler(int handle, BinaryObject po) {
-        assert po != null;
-
-        if (poHandles == null)
-            poHandles = new HashMap<>(3, 1.0f);
-
-        poHandles.put(handle, po);
-    }
-
-    /**
-     * @param handle Handle.
-     * @return Object.
-     */
-    @Nullable Object getObjectByHandle(int handle) {
-        if (oHandles != null) {
-            if (oHandles instanceof IgniteBiTuple) {
-                IgniteBiTuple t = (IgniteBiTuple)oHandles;
-
-                if ((int)t.get1() == handle)
-                    return t.get2();
-            }
-            else
-                return ((Map)oHandles).get(handle);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param handle Handle.
-     * @return Object.
-     */
-    @Nullable BinaryObject getPortableByHandle(int handle) {
-        return poHandles != null ? poHandles.get(handle) : null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(PortableReaderContext.class, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableSchema.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableSchema.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableSchema.java
index 86ca5f8..72a96b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableSchema.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableSchema.java
@@ -17,14 +17,11 @@
 
 package org.apache.ignite.internal.portable;
 
-import org.apache.ignite.internal.util.typedef.internal.U;
-
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 
@@ -41,14 +38,26 @@ public class PortableSchema implements Externalizable {
     /** Order returned if field is not found. */
     public static final int ORDER_NOT_FOUND = -1;
 
-    /** Inline flag. */
-    private boolean inline;
+    /** Minimum sensible size. */
+    private static final int MAP_MIN_SIZE = 32;
 
-    /** Map with ID to order. */
-    private HashMap<Integer, Integer> idToOrder;
+    /** Empty cell. */
+    private static final int MAP_EMPTY = 0;
+
+    /** Schema ID. */
+    private int schemaId;
 
     /** IDs depending on order. */
-    private ArrayList<Integer> ids;
+    private int[] ids;
+
+    /** Interned names of associated fields. */
+    private String[] names;
+
+    /** ID-to-order data. */
+    private int[] idToOrderData;
+
+    /** ID-to-order mask. */
+    private int idToOrderMask;
 
     /** ID 1. */
     private int id0;
@@ -62,21 +71,6 @@ public class PortableSchema implements Externalizable {
     /** ID 4. */
     private int id3;
 
-    /** ID 1. */
-    private int id4;
-
-    /** ID 2. */
-    private int id5;
-
-    /** ID 3. */
-    private int id6;
-
-    /** ID 4. */
-    private int id7;
-
-    /** Schema ID. */
-    private int schemaId;
-
     /**
      * {@link Externalizable} support.
      */
@@ -91,39 +85,11 @@ public class PortableSchema implements Externalizable {
      * @param fieldIds Field IDs.
      */
     private PortableSchema(int schemaId, List<Integer> fieldIds) {
-        this.schemaId = schemaId;
+        assert fieldIds != null;
 
-        if (fieldIds.size() <= 8) {
-            inline = true;
-
-            Iterator<Integer> iter = fieldIds.iterator();
-
-            id0 = iter.hasNext() ? iter.next() : 0;
-            id1 = iter.hasNext() ? iter.next() : 0;
-            id2 = iter.hasNext() ? iter.next() : 0;
-            id3 = iter.hasNext() ? iter.next() : 0;
-            id4 = iter.hasNext() ? iter.next() : 0;
-            id5 = iter.hasNext() ? iter.next() : 0;
-            id6 = iter.hasNext() ? iter.next() : 0;
-            id7 = iter.hasNext() ? iter.next() : 0;
-
-            idToOrder = null;
-        }
-        else {
-            inline = false;
-
-            id0 = id1 = id2 = id3 = id4 = id5 = id6 = id7 = 0;
-
-            ids = new ArrayList<>();
-            idToOrder = new HashMap<>();
-
-            for (int i = 0; i < fieldIds.size(); i++) {
-                int fieldId = fieldIds.get(i);
+        this.schemaId = schemaId;
 
-                ids.add(fieldId);
-                idToOrder.put(fieldId, i);
-            }
-        }
+        initialize(fieldIds);
     }
 
     /**
@@ -134,46 +100,51 @@ public class PortableSchema implements Externalizable {
     }
 
     /**
-     * Get field ID by order in footer.
+     * Try speculatively confirming order for the given field name.
      *
-     * @param order Order.
+     * @param expOrder Expected order.
+     * @param expName Expected name.
      * @return Field ID.
      */
-    public int fieldId(int order) {
-        if (inline) {
-            switch (order) {
-                case 0:
-                    return id0;
+    @SuppressWarnings("StringEquality")
+    public Confirmation confirmOrder(int expOrder, String expName) {
+        assert expName != null;
 
-                case 1:
-                    return id1;
+        if (expOrder < names.length) {
+            String name = names[expOrder];
 
-                case 2:
-                    return id2;
+            // Note that we use only reference equality assuming that field names are interned literals.
+            if (name == expName)
+                return Confirmation.CONFIRMED;
 
-                case 3:
-                    return id3;
-
-                case 4:
-                    return id4;
-
-                case 5:
-                    return id5;
+            if (name == null)
+                return Confirmation.CLARIFY;
+        }
 
-                case 6:
-                    return id6;
+        return Confirmation.REJECTED;
+    }
 
-                case 7:
-                    return id7;
+    /**
+     * Add field name.
+     *
+     * @param order Order.
+     * @param name Name.
+     */
+    public void clarifyFieldName(int order, String name) {
+        assert name != null;
+        assert order < names.length;
 
-                default:
-                    assert false : "Should not reach here.";
+        names[order] = name.intern();
+    }
 
-                    return 0;
-            }
-        }
-        else
-            return ids.get(order);
+    /**
+     * Get field ID by order in footer.
+     *
+     * @param order Order.
+     * @return Field ID.
+     */
+    public int fieldId(int order) {
+        return order < ids.length ? ids[order] : 0;
     }
 
     /**
@@ -183,7 +154,7 @@ public class PortableSchema implements Externalizable {
      * @return Offset or {@code 0} if there is no such field.
      */
     public int order(int id) {
-        if (inline) {
+        if (idToOrderData == null) {
             if (id == id0)
                 return 0;
 
@@ -196,24 +167,34 @@ public class PortableSchema implements Externalizable {
             if (id == id3)
                 return 3;
 
-            if (id == id4)
-                return 4;
+            return ORDER_NOT_FOUND;
+        }
+        else {
+            int idx = (id & idToOrderMask) << 1;
+
+            int curId = idToOrderData[idx];
 
-            if (id == id5)
-                return 5;
+            if (id == curId) // Hit!
+                return idToOrderData[idx + 1];
+            else if (curId == MAP_EMPTY) // No such ID!
+                return ORDER_NOT_FOUND;
+            else {
+                // Unlikely collision scenario.
+                for (int i = 2; i < idToOrderData.length; i += 2) {
+                    int newIdx = (idx + i) % idToOrderData.length;
 
-            if (id == id6)
-                return 6;
+                    assert newIdx < idToOrderData.length - 1;
 
-            if (id == id7)
-                return 7;
+                    curId = idToOrderData[newIdx];
 
-            return ORDER_NOT_FOUND;
-        }
-        else {
-            Integer order = idToOrder.get(id);
+                    if (id == curId)
+                        return idToOrderData[newIdx + 1];
+                    else if (curId == MAP_EMPTY)
+                        return ORDER_NOT_FOUND;
+                }
 
-            return order != null ? order : ORDER_NOT_FOUND;
+                return ORDER_NOT_FOUND;
+            }
         }
     }
 
@@ -231,59 +212,173 @@ public class PortableSchema implements Externalizable {
     @Override public void writeExternal(ObjectOutput out) throws IOException {
         out.writeInt(schemaId);
 
-        if (inline) {
-            out.writeBoolean(true);
-
-            out.writeInt(id0);
-            out.writeInt(id1);
-            out.writeInt(id2);
-            out.writeInt(id3);
-            out.writeInt(id4);
-            out.writeInt(id5);
-            out.writeInt(id6);
-            out.writeInt(id7);
-        }
-        else {
-            out.writeBoolean(false);
-
-            out.writeInt(ids.size());
+        out.writeInt(ids.length);
 
-            for (Integer id : ids)
-                out.writeInt(id);
-        }
+        for (Integer id : ids)
+            out.writeInt(id);
     }
 
     /** {@inheritDoc} */
     @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         schemaId = in.readInt();
 
-        if (in.readBoolean()) {
-            inline = true;
-
-            id0 = in.readInt();
-            id1 = in.readInt();
-            id2 = in.readInt();
-            id3 = in.readInt();
-            id4 = in.readInt();
-            id5 = in.readInt();
-            id6 = in.readInt();
-            id7 = in.readInt();
+        int idsCnt = in.readInt();
+
+        List<Integer> fieldIds = new ArrayList<>(idsCnt);
+
+        for (int i = 0; i < idsCnt; i++)
+            fieldIds.add(in.readInt());
+
+        initialize(fieldIds);
+    }
+
+    /**
+     * Parse values.
+     *
+     * @param vals Values.
+     * @param size Proposed result size.
+     * @return Parse result.
+     */
+    private static ParseResult parse(int[] vals, int size) {
+        int mask = maskForPowerOfTwo(size);
+
+        int totalSize = size * 2;
+
+        int[] data = new int[totalSize];
+        int collisions = 0;
+
+        for (int order = 0; order < vals.length; order++) {
+            int id = vals[order];
+
+            assert id != 0;
+
+            int idIdx = (id & mask) << 1;
+
+            if (data[idIdx] == 0) {
+                // Found empty slot.
+                data[idIdx] = id;
+                data[idIdx + 1] = order;
+            }
+            else {
+                // Collision!
+                collisions++;
+
+                boolean placeFound = false;
+
+                for (int i = 2; i < totalSize; i += 2) {
+                    int newIdIdx = (idIdx + i) % totalSize;
+
+                    if (data[newIdIdx] == 0) {
+                        data[newIdIdx] = id;
+                        data[newIdIdx + 1] = order;
+
+                        placeFound = true;
+
+                        break;
+                    }
+                }
+
+                assert placeFound : "Should always have a place for entry!";
+            }
+        }
+
+        return new ParseResult(data, collisions);
+    }
+
+    /**
+     * Get next power of two which greater or equal to the given number.
+     * This implementation is not meant to be very efficient, so it is expected to be used relatively rare.
+     *
+     * @param val Number
+     * @return Nearest pow2.
+     */
+    private static int nextPowerOfTwo(int val) {
+        int res = 1;
+
+        while (res < val)
+            res = res << 1;
+
+        if (res < 0)
+            throw new IllegalArgumentException("Value is too big to find positive pow2: " + val);
+
+        return res;
+    }
+
+    /**
+     * Calculate mask for the given value which is a power of two.
+     *
+     * @param val Value.
+     * @return Mask.
+     */
+    private static int maskForPowerOfTwo(int val) {
+        int mask = 0;
+        int comparand = 1;
+
+        while (comparand < val) {
+            mask |= comparand;
+
+            comparand <<= 1;
+        }
+
+        return mask;
+    }
+
+    /**
+     * Initialization routine.
+     *
+     * @param fieldIds Field IDs.
+     */
+    private void initialize(List<Integer> fieldIds) {
+        ids = new int[fieldIds.size()];
+
+        for (int i = 0; i < fieldIds.size(); i++)
+            ids[i] = fieldIds.get(i);
+
+        names = new String[fieldIds.size()];
+
+        if (fieldIds.size() <= 4) {
+            Iterator<Integer> iter = fieldIds.iterator();
+
+            id0 = iter.hasNext() ? iter.next() : 0;
+            id1 = iter.hasNext() ? iter.next() : 0;
+            id2 = iter.hasNext() ? iter.next() : 0;
+            id3 = iter.hasNext() ? iter.next() : 0;
         }
         else {
-            inline = false;
+            id0 = id1 = id2 = id3 = 0;
 
-            int size = in.readInt();
+            initializeMap(ids);
+        }
+    }
 
-            ids = new ArrayList<>(size);
-            idToOrder = U.newHashMap(size);
+    /**
+     * Initialize the map.
+     *
+     * @param vals Values.
+     */
+    private void initializeMap(int[] vals) {
+        int size = Math.max(nextPowerOfTwo(vals.length) << 2, MAP_MIN_SIZE);
 
-            for (int i = 0; i < size; i++) {
-                int fieldId = in.readInt();
+        assert size > 0;
 
-                ids.add(fieldId);
-                idToOrder.put(fieldId, i);
-            }
+        ParseResult finalRes;
+
+        ParseResult res1 = parse(vals, size);
+
+        if (res1.collisions == 0)
+            finalRes = res1;
+        else {
+            ParseResult res2 = parse(vals, size * 2);
+
+            // Failed to decrease aom
+            if (res2.collisions == 0)
+                finalRes = res2;
+            else
+                finalRes = parse(vals, size * 4);
         }
+
+        idToOrderData = finalRes.data;
+        idToOrderMask = maskForPowerOfTwo(idToOrderData.length / 2);
     }
 
     /**
@@ -332,4 +427,40 @@ public class PortableSchema implements Externalizable {
             return new PortableSchema(schemaId, fields);
         }
     }
+
+    /**
+     * Order confirmation result.
+     */
+    public enum Confirmation {
+        /** Confirmed. */
+        CONFIRMED,
+
+        /** Denied. */
+        REJECTED,
+
+        /** Field name clarification is needed. */
+        CLARIFY
+    }
+
+    /**
+     * Result of map parsing.
+     */
+    private static class ParseResult {
+        /** Data. */
+        private int[] data;
+
+        /** Collisions. */
+        private int collisions;
+
+        /**
+         * Constructor.
+         *
+         * @param data Data.
+         * @param collisions Collisions.
+         */
+        private ParseResult(int[] data, int collisions) {
+            this.data = data;
+            this.collisions = collisions;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableThreadLocalMemoryAllocator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableThreadLocalMemoryAllocator.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableThreadLocalMemoryAllocator.java
deleted file mode 100644
index 8f5bfb2..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableThreadLocalMemoryAllocator.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.portable;
-
-import org.apache.ignite.internal.portable.streams.PortableMemoryAllocator;
-import org.apache.ignite.internal.util.GridUnsafe;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import sun.misc.Unsafe;
-
-import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHAL_BUFFERS_RECHECK;
-
-/**
- * Thread-local memory allocator.
- */
-public class PortableThreadLocalMemoryAllocator implements PortableMemoryAllocator {
-    /** Memory allocator instance. */
-    public static final PortableThreadLocalMemoryAllocator THREAD_LOCAL_ALLOC =
-        new PortableThreadLocalMemoryAllocator();
-
-    /** Holders. */
-    private static final ThreadLocal<ByteArrayHolder> holders = new ThreadLocal<>();
-
-    /** Unsafe instance. */
-    protected static final Unsafe UNSAFE = GridUnsafe.unsafe();
-
-    /** Array offset: byte. */
-    protected static final long BYTE_ARR_OFF = UNSAFE.arrayBaseOffset(byte[].class);
-
-    /**
-     * Ensures singleton.
-     */
-    private PortableThreadLocalMemoryAllocator() {
-        // No-op.
-    }
-
-    /** {@inheritDoc} */
-    @Override public byte[] allocate(int size) {
-        ByteArrayHolder holder = holders.get();
-
-        if (holder == null)
-            holders.set(holder = new ByteArrayHolder());
-
-        if (holder.acquired)
-            return new byte[size];
-
-        holder.acquired = true;
-
-        if (holder.data == null || size > holder.data.length)
-            holder.data = new byte[size];
-
-        return holder.data;
-    }
-
-    /** {@inheritDoc} */
-    @Override public byte[] reallocate(byte[] data, int size) {
-        ByteArrayHolder holder = holders.get();
-
-        assert holder != null;
-
-        byte[] newData = new byte[size];
-
-        if (holder.data == data)
-            holder.data = newData;
-
-        UNSAFE.copyMemory(data, BYTE_ARR_OFF, newData, BYTE_ARR_OFF, data.length);
-
-        return newData;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void release(byte[] data, int maxMsgSize) {
-        ByteArrayHolder holder = holders.get();
-
-        assert holder != null;
-
-        if (holder.data != data)
-            return;
-
-        holder.maxMsgSize = maxMsgSize;
-        holder.acquired = false;
-
-        holder.shrink();
-    }
-
-    /** {@inheritDoc} */
-    @Override public long allocateDirect(int size) {
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override public long reallocateDirect(long addr, int size) {
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void releaseDirect(long addr) {
-        // No-op
-    }
-
-    /**
-     * Checks whether a thread-local array is acquired or not.
-     * The function is used by Unit tests.
-     *
-     * @return {@code true} if acquired {@code false} otherwise.
-     */
-    public boolean isThreadLocalArrayAcquired() {
-        ByteArrayHolder holder = holders.get();
-
-        return holder != null && holder.acquired;
-    }
-
-    /**
-     * Thread-local byte array holder.
-     */
-    private static class ByteArrayHolder {
-        /** */
-        private static final Long CHECK_FREQ = Long.getLong(IGNITE_MARSHAL_BUFFERS_RECHECK, 10000);
-
-        /** Data array */
-        private byte[] data;
-
-        /** Max message size detected between checks. */
-        private int maxMsgSize;
-
-        /** Last time array size is checked. */
-        private long lastCheck = U.currentTimeMillis();
-
-        /** Whether the holder is acquired or not. */
-        private boolean acquired;
-
-        /**
-         * Shrinks array size if needed.
-         */
-        private void shrink() {
-            long now = U.currentTimeMillis();
-
-            if (now - lastCheck >= CHECK_FREQ) {
-                int halfSize = data.length >> 1;
-
-                if (maxMsgSize < halfSize)
-                    data = new byte[halfSize];
-
-                lastCheck = now;
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
index 95ef9591..53d414c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
@@ -17,7 +17,9 @@
 
 package org.apache.ignite.internal.portable;
 
+import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.internal.portable.builder.PortableLazyValue;
+import org.apache.ignite.internal.portable.streams.PortableOutputStream;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
@@ -26,6 +28,7 @@ import org.apache.ignite.binary.BinaryObject;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 
+import java.io.Externalizable;
 import java.math.BigDecimal;
 import java.sql.Timestamp;
 import java.util.Collection;
@@ -669,13 +672,14 @@ public class PortableUtils {
      * @return Position where length should be written.
      */
     public static int writeHeader(BinaryWriterExImpl writer, int typeId, int hashCode, @Nullable String clsName) {
-        writer.doWriteByte(GridPortableMarshaller.OBJ);
-        writer.doWriteByte(GridPortableMarshaller.PROTO_VER);
+        PortableOutputStream out = writer.out();
 
-        writer.doWriteShort((short) 0);
-
-        writer.doWriteInt(typeId);
-        writer.doWriteInt(hashCode);
+        out.unsafeEnsure(12);
+        out.unsafeWriteByte(GridPortableMarshaller.OBJ);
+        out.unsafeWriteByte(GridPortableMarshaller.PROTO_VER);
+        out.unsafeWriteShort((short) 0);
+        out.unsafeWriteInt(typeId);
+        out.unsafeWriteInt(hashCode);
 
         int reserved = writer.reserve(12);
 
@@ -903,4 +907,108 @@ public class PortableUtils {
                 oldMeta.affinityKeyFieldName(), mergedSchemas) : oldMeta;
         }
     }
+
+    /**
+     * @param cls Class.
+     * @return Mode.
+     */
+    @SuppressWarnings("IfMayBeConditional")
+    public static BinaryWriteMode mode(Class<?> cls) {
+        assert cls != null;
+
+        /** Primitives. */
+        if (cls == byte.class)
+            return BinaryWriteMode.P_BYTE;
+        else if (cls == boolean.class)
+            return BinaryWriteMode.P_BOOLEAN;
+        else if (cls == short.class)
+            return BinaryWriteMode.P_SHORT;
+        else if (cls == char.class)
+            return BinaryWriteMode.P_CHAR;
+        else if (cls == int.class)
+            return BinaryWriteMode.P_INT;
+        else if (cls == long.class)
+            return BinaryWriteMode.P_LONG;
+        else if (cls == float.class)
+            return BinaryWriteMode.P_FLOAT;
+        else if (cls == double.class)
+            return BinaryWriteMode.P_DOUBLE;
+
+        /** Boxed primitives. */
+        else if (cls == Byte.class)
+            return BinaryWriteMode.BYTE;
+        else if (cls == Boolean.class)
+            return BinaryWriteMode.BOOLEAN;
+        else if (cls == Short.class)
+            return BinaryWriteMode.SHORT;
+        else if (cls == Character.class)
+            return BinaryWriteMode.CHAR;
+        else if (cls == Integer.class)
+            return BinaryWriteMode.INT;
+        else if (cls == Long.class)
+            return BinaryWriteMode.LONG;
+        else if (cls == Float.class)
+            return BinaryWriteMode.FLOAT;
+        else if (cls == Double.class)
+            return BinaryWriteMode.DOUBLE;
+
+        /** The rest types. */
+        else if (cls == BigDecimal.class)
+            return BinaryWriteMode.DECIMAL;
+        else if (cls == String.class)
+            return BinaryWriteMode.STRING;
+        else if (cls == UUID.class)
+            return BinaryWriteMode.UUID;
+        else if (cls == Date.class)
+            return BinaryWriteMode.DATE;
+        else if (cls == Timestamp.class)
+            return BinaryWriteMode.TIMESTAMP;
+        else if (cls == byte[].class)
+            return BinaryWriteMode.BYTE_ARR;
+        else if (cls == short[].class)
+            return BinaryWriteMode.SHORT_ARR;
+        else if (cls == int[].class)
+            return BinaryWriteMode.INT_ARR;
+        else if (cls == long[].class)
+            return BinaryWriteMode.LONG_ARR;
+        else if (cls == float[].class)
+            return BinaryWriteMode.FLOAT_ARR;
+        else if (cls == double[].class)
+            return BinaryWriteMode.DOUBLE_ARR;
+        else if (cls == char[].class)
+            return BinaryWriteMode.CHAR_ARR;
+        else if (cls == boolean[].class)
+            return BinaryWriteMode.BOOLEAN_ARR;
+        else if (cls == BigDecimal[].class)
+            return BinaryWriteMode.DECIMAL_ARR;
+        else if (cls == String[].class)
+            return BinaryWriteMode.STRING_ARR;
+        else if (cls == UUID[].class)
+            return BinaryWriteMode.UUID_ARR;
+        else if (cls == Date[].class)
+            return BinaryWriteMode.DATE_ARR;
+        else if (cls == Timestamp[].class)
+            return BinaryWriteMode.TIMESTAMP_ARR;
+        else if (cls.isArray())
+            return cls.getComponentType().isEnum() ?
+                BinaryWriteMode.ENUM_ARR : BinaryWriteMode.OBJECT_ARR;
+        else if (cls == BinaryObjectImpl.class)
+            return BinaryWriteMode.PORTABLE_OBJ;
+        else if (Binarylizable.class.isAssignableFrom(cls))
+            return BinaryWriteMode.PORTABLE;
+        else if (Externalizable.class.isAssignableFrom(cls))
+            return BinaryWriteMode.EXTERNALIZABLE;
+        else if (Map.Entry.class.isAssignableFrom(cls))
+            return BinaryWriteMode.MAP_ENTRY;
+        else if (Collection.class.isAssignableFrom(cls))
+            return BinaryWriteMode.COL;
+        else if (Map.class.isAssignableFrom(cls))
+            return BinaryWriteMode.MAP;
+        else if (cls.isEnum())
+            return BinaryWriteMode.ENUM;
+        else if (cls == Class.class)
+            return BinaryWriteMode.CLASS;
+        else
+            return BinaryWriteMode.OBJECT;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
index dfc2330..2ce2416 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
@@ -178,7 +178,9 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
 
     /** {@inheritDoc} */
     @Override public BinaryObject build() {
-        try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, typeId, false)) {
+        try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx)) {
+            writer.typeId(typeId);
+
             PortableBuilderSerializer serializationCtx = new PortableBuilderSerializer();
 
             serializationCtx.registerObjectWriting(this, 0);
@@ -206,7 +208,7 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
             Set<Integer> remainsFlds = null;
 
             if (reader != null) {
-                PortableSchema schema = reader.schema(start);
+                PortableSchema schema = reader.schema();
 
                 Map<Integer, Object> assignedFldsById;
 
@@ -440,7 +442,7 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
             int fieldIdLen = PortableUtils.fieldIdLength(flags);
             int fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
 
-            PortableSchema schema = reader.schema(start);
+            PortableSchema schema = reader.schema();
 
             Map<Integer, Object> readCache = new HashMap<>();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderReader.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderReader.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderReader.java
index b6a6b54..538c26c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderReader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderReader.java
@@ -21,6 +21,8 @@ import java.sql.Timestamp;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
+
+import org.apache.ignite.internal.portable.BinaryReaderHandles;
 import org.apache.ignite.internal.portable.GridPortableMarshaller;
 import org.apache.ignite.internal.portable.PortableContext;
 import org.apache.ignite.internal.portable.PortablePositionReadable;
@@ -31,6 +33,7 @@ import org.apache.ignite.internal.portable.PortableSchema;
 import org.apache.ignite.internal.portable.PortableUtils;
 import org.apache.ignite.internal.portable.BinaryWriterExImpl;
 import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.internal.portable.streams.PortableHeapInputStream;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.NULL;
@@ -41,21 +44,23 @@ import static org.apache.ignite.internal.portable.GridPortableMarshaller.STRING;
  */
 public class PortableBuilderReader implements PortablePositionReadable {
     /** */
-    private final Map<Integer, BinaryObjectBuilderImpl> objMap = new HashMap<>();
+    private final PortableContext ctx;
 
     /** */
-    private final PortableContext ctx;
+    private final byte[] arr;
 
     /** */
     private final BinaryReaderExImpl reader;
 
     /** */
-    private byte[] arr;
+    private final Map<Integer, BinaryObjectBuilderImpl> objMap;
 
     /** */
     private int pos;
 
-    /**
+    /*
+     * Constructor.
+     *
      * @param objImpl Portable object
      */
     PortableBuilderReader(BinaryObjectImpl objImpl) {
@@ -64,7 +69,25 @@ public class PortableBuilderReader implements PortablePositionReadable {
         pos = objImpl.start();
 
         // TODO: IGNITE-1272 - Is class loader needed here?
-        reader = new BinaryReaderExImpl(ctx, arr, pos, null);
+        reader = new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, pos), null, new BinaryReaderHandles());
+
+        objMap = new HashMap<>();
+    }
+
+    /**
+     * Copying constructor.
+     *
+     * @param other Other reader.
+     * @param start Start position.
+     */
+    PortableBuilderReader(PortableBuilderReader other, int start) {
+        this.ctx = other.ctx;
+        this.arr = other.arr;
+        this.pos = start;
+
+        reader = new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, start), null, other.reader.handles());
+
+        this.objMap = other.objMap;
     }
 
     /**
@@ -84,19 +107,10 @@ public class PortableBuilderReader implements PortablePositionReadable {
     /**
      * Get schema of the object, starting at the given position.
      *
-     * @param start Start position.
      * @return Object's schema.
      */
-    public PortableSchema schema(int start) {
-        // We can use current reader in case start is equal to initially recorded position.
-        BinaryReaderExImpl targetReader;
-
-        if (start == pos)
-            targetReader = reader;
-        else
-            targetReader = new BinaryReaderExImpl(ctx, arr, start, null);
-
-        return targetReader.getOrCreateSchema();
+    public PortableSchema schema() {
+        return reader.getOrCreateSchema();
     }
 
     /**
@@ -367,7 +381,7 @@ public class PortableBuilderReader implements PortablePositionReadable {
                 BinaryObjectBuilderImpl res = objMap.get(objStart);
 
                 if (res == null) {
-                    res = new BinaryObjectBuilderImpl(this, objStart);
+                    res = new BinaryObjectBuilderImpl(new PortableBuilderReader(this, objStart), objStart);
 
                     objMap.put(objStart, res);
                 }
@@ -379,7 +393,7 @@ public class PortableBuilderReader implements PortablePositionReadable {
                 BinaryObjectBuilderImpl res = objMap.get(pos);
 
                 if (res == null) {
-                    res = new BinaryObjectBuilderImpl(this, pos);
+                    res = new BinaryObjectBuilderImpl(new PortableBuilderReader(this, pos), pos);
 
                     objMap.put(pos, res);
                 }
@@ -492,7 +506,7 @@ public class PortableBuilderReader implements PortablePositionReadable {
                 BinaryObjectBuilderImpl res = objMap.get(objStart);
 
                 if (res == null) {
-                    res = new BinaryObjectBuilderImpl(this, objStart);
+                    res = new BinaryObjectBuilderImpl(new PortableBuilderReader(this, objStart), objStart);
 
                     objMap.put(objStart, res);
                 }
@@ -506,7 +520,7 @@ public class PortableBuilderReader implements PortablePositionReadable {
                 BinaryObjectBuilderImpl res = objMap.get(pos);
 
                 if (res == null) {
-                    res = new BinaryObjectBuilderImpl(this, pos);
+                    res = new BinaryObjectBuilderImpl(new PortableBuilderReader(this, pos), pos);
 
                     objMap.put(pos, res);
                 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableAbstractOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableAbstractOutputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableAbstractOutputStream.java
index c943682..b68e9d1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableAbstractOutputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableAbstractOutputStream.java
@@ -123,14 +123,14 @@ public abstract class PortableAbstractOutputStream extends PortableAbstractStrea
     @Override public void writeShort(int pos, short val) {
         ensureCapacity(pos + 2);
 
-        writeShortPositioned(pos, val);
+        unsafeWriteShort(pos, val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeInt(int pos, int val) {
         ensureCapacity(pos + 4);
 
-        writeIntPositioned(pos, val);
+        unsafeWriteInt(pos, val);
     }
 
     /** {@inheritDoc} */
@@ -247,6 +247,26 @@ public abstract class PortableAbstractOutputStream extends PortableAbstractStrea
         return 0;
     }
 
+    /** {@inheritDoc} */
+    @Override public void unsafeEnsure(int cap) {
+        ensureCapacity(pos + cap);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteBoolean(boolean val) {
+        unsafeWriteByte(val ? BYTE_ONE : BYTE_ZERO);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteFloat(float val) {
+        unsafeWriteInt(Float.floatToIntBits(val));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteDouble(double val) {
+        unsafeWriteLong(Double.doubleToLongBits(val));
+    }
+
     /**
      * Calculate new capacity.
      *
@@ -314,22 +334,6 @@ public abstract class PortableAbstractOutputStream extends PortableAbstractStrea
     protected abstract void writeLongFast(long val);
 
     /**
-     * Write short value to the given position.
-     *
-     * @param pos Position.
-     * @param val Value.
-     */
-    protected abstract void writeShortPositioned(int pos, short val);
-
-    /**
-     * Write int value to the given position.
-     *
-     * @param pos Position.
-     * @param val Value.
-     */
-    protected abstract void writeIntPositioned(int pos, int val);
-
-    /**
      * Ensure capacity.
      *
      * @param cnt Required byte count.

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapInputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapInputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapInputStream.java
index e027d70..1b39950 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapInputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapInputStream.java
@@ -23,6 +23,23 @@ import java.util.Arrays;
  * Portable off-heap input stream.
  */
 public final class PortableHeapInputStream extends PortableAbstractInputStream {
+    /**
+     * Create stream with pointer set at the given position.
+     *
+     * @param data Data.
+     * @param pos Position.
+     * @return Stream.
+     */
+    public static PortableHeapInputStream create(byte[] data, int pos) {
+        assert pos < data.length;
+
+        PortableHeapInputStream stream = new PortableHeapInputStream(data);
+
+        stream.pos = pos;
+
+        return stream;
+    }
+
     /** Data. */
     private byte[] data;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapOutputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapOutputStream.java
index 208ad33..062a359 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapOutputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableHeapOutputStream.java
@@ -17,73 +17,40 @@
 
 package org.apache.ignite.internal.portable.streams;
 
-import static org.apache.ignite.internal.portable.PortableThreadLocalMemoryAllocator.DFLT_ALLOC;
-import static org.apache.ignite.internal.portable.PortableThreadLocalMemoryAllocator.THREAD_LOCAL_ALLOC;
-
 /**
  * Portable heap output stream.
  */
 public final class PortableHeapOutputStream extends PortableAbstractOutputStream {
-    /** Default capacity. */
-    private static final int DFLT_CAP = 1024;
-
     /** Allocator. */
-    private final PortableMemoryAllocator alloc;
+    private final PortableMemoryAllocatorChunk chunk;
 
     /** Data. */
     private byte[] data;
 
     /**
      * Constructor.
-     */
-    public PortableHeapOutputStream() {
-        this(DFLT_CAP, DFLT_ALLOC);
-    }
-
-    /**
-     * Constructor.
      *
      * @param cap Initial capacity.
      */
     public PortableHeapOutputStream(int cap) {
-        this(cap, THREAD_LOCAL_ALLOC);
+        this(cap, PortableMemoryAllocator.INSTANCE.chunk());
     }
 
     /**
      * Constructor.
      *
-     * @param cap Initial capacity.
-     * @param alloc Allocator.
+     * @param cap Capacity.
+     * @param chunk Chunk.
      */
-    public PortableHeapOutputStream(int cap, PortableMemoryAllocator alloc) {
-        data = alloc.allocate(cap);
-
-        this.alloc = alloc;
-    }
+    public PortableHeapOutputStream(int cap, PortableMemoryAllocatorChunk chunk) {
+        this.chunk = chunk;
 
-    /**
-     * Constructor.
-     *
-     * @param data Data.
-     */
-    public PortableHeapOutputStream(byte[] data) {
-        this(data, DFLT_ALLOC);
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param data Data.
-     * @param alloc Allocator.
-     */
-    public PortableHeapOutputStream(byte[] data, PortableMemoryAllocator alloc) {
-        this.data = data;
-        this.alloc = alloc;
+        data = chunk.allocate(cap);
     }
 
     /** {@inheritDoc} */
     @Override public void close() {
-        alloc.release(data, pos);
+        chunk.release(data, pos);
     }
 
     /** {@inheritDoc} */
@@ -91,7 +58,7 @@ public final class PortableHeapOutputStream extends PortableAbstractOutputStream
         if (cnt > data.length) {
             int newCap = capacity(data.length, cnt);
 
-            data = alloc.reallocate(data, newCap);
+            data = chunk.reallocate(data, newCap);
         }
     }
 
@@ -147,18 +114,63 @@ public final class PortableHeapOutputStream extends PortableAbstractOutputStream
     }
 
     /** {@inheritDoc} */
-    @Override protected void writeShortPositioned(int pos, short val) {
+    @Override public void unsafeWriteByte(byte val) {
+        UNSAFE.putByte(data, BYTE_ARR_OFF + pos++, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(short val) {
         if (!LITTLE_ENDIAN)
             val = Short.reverseBytes(val);
 
         UNSAFE.putShort(data, BYTE_ARR_OFF + pos, val);
+
+        shift(2);
     }
 
     /** {@inheritDoc} */
-    @Override protected void writeIntPositioned(int pos, int val) {
+    @Override public void unsafeWriteShort(int pos, short val) {
+        if (!LITTLE_ENDIAN)
+            val = Short.reverseBytes(val);
+
+        UNSAFE.putShort(data, BYTE_ARR_OFF + pos, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteChar(char val) {
+        if (!LITTLE_ENDIAN)
+            val = Character.reverseBytes(val);
+
+        UNSAFE.putChar(data, BYTE_ARR_OFF + pos, val);
+
+        shift(2);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int val) {
+        if (!LITTLE_ENDIAN)
+            val = Integer.reverseBytes(val);
+
+        UNSAFE.putInt(data, BYTE_ARR_OFF + pos, val);
+
+        shift(4);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteInt(int pos, int val) {
         if (!LITTLE_ENDIAN)
             val = Integer.reverseBytes(val);
 
         UNSAFE.putInt(data, BYTE_ARR_OFF + pos, val);
     }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteLong(long val) {
+        if (!LITTLE_ENDIAN)
+            val = Long.reverseBytes(val);
+
+        UNSAFE.putLong(data, BYTE_ARR_OFF + pos, val);
+
+        shift(8);
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocator.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocator.java
index 7ddb457..e16747b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocator.java
@@ -18,59 +18,40 @@
 package org.apache.ignite.internal.portable.streams;
 
 /**
- * Portable memory allocator.
+ * Thread-local memory allocator.
  */
-public interface PortableMemoryAllocator {
-    /** Default memory allocator. */
-    public static final PortableMemoryAllocator DFLT_ALLOC = new PortableSimpleMemoryAllocator();
+public final class PortableMemoryAllocator {
+    /** Memory allocator instance. */
+    public static final PortableMemoryAllocator INSTANCE = new PortableMemoryAllocator();
 
-    /**
-     * Allocate memory.
-     *
-     * @param size Size.
-     * @return Data.
-     */
-    public byte[] allocate(int size);
+    /** Holders. */
+    private static final ThreadLocal<PortableMemoryAllocatorChunk> holders = new ThreadLocal<>();
 
     /**
-     * Reallocates memory.
-     *
-     * @param data Current data chunk.
-     * @param size New size required.
-     *
-     * @return Data.
+     * Ensures singleton.
      */
-    public byte[] reallocate(byte[] data, int size);
+    private PortableMemoryAllocator() {
+        // No-op.
+    }
 
-    /**
-     * Release memory.
-     *
-     * @param data Data.
-     * @param maxMsgSize Max message size sent during the time the allocator is used.
-     */
-    public void release(byte[] data, int maxMsgSize);
+    public PortableMemoryAllocatorChunk chunk() {
+        PortableMemoryAllocatorChunk holder = holders.get();
 
-    /**
-     * Allocate memory.
-     *
-     * @param size Size.
-     * @return Address.
-     */
-    public long allocateDirect(int size);
+        if (holder == null)
+            holders.set(holder = new PortableMemoryAllocatorChunk());
 
-    /**
-     * Reallocate memory.
-     *
-     * @param addr Address.
-     * @param size Size.
-     * @return Address.
-     */
-    public long reallocateDirect(long addr, int size);
+        return holder;
+    }
 
     /**
-     * Release memory.
+     * Checks whether a thread-local array is acquired or not.
+     * The function is used by Unit tests.
      *
-     * @param addr Address.
+     * @return {@code true} if acquired {@code false} otherwise.
      */
-    public void releaseDirect(long addr);
+    public boolean isAcquired() {
+        PortableMemoryAllocatorChunk holder = holders.get();
+
+        return holder != null && holder.isAcquired();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocatorChunk.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocatorChunk.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocatorChunk.java
new file mode 100644
index 0000000..35d58f7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableMemoryAllocatorChunk.java
@@ -0,0 +1,117 @@
+/*
+ * 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.portable.streams;
+
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import sun.misc.Unsafe;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHAL_BUFFERS_RECHECK;
+
+/**
+ * Memory allocator chunk.
+ */
+public class PortableMemoryAllocatorChunk {
+    /** Unsafe instance. */
+    protected static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+    /** Array offset: byte. */
+    protected static final long BYTE_ARR_OFF = UNSAFE.arrayBaseOffset(byte[].class);
+
+    /** Buffer size re-check frequency. */
+    private static final Long CHECK_FREQ = Long.getLong(IGNITE_MARSHAL_BUFFERS_RECHECK, 10000);
+
+    /** Data array */
+    private byte[] data;
+
+    /** Max message size detected between checks. */
+    private int maxMsgSize;
+
+    /** Last time array size is checked. */
+    private long lastCheck = U.currentTimeMillis();
+
+    /** Whether the holder is acquired or not. */
+    private boolean acquired;
+
+    /**
+     * Allocate.
+     *
+     * @param size Desired size.
+     * @return Data.
+     */
+    public byte[] allocate(int size) {
+        if (acquired)
+            return new byte[size];
+
+        acquired = true;
+
+        if (data == null || size > data.length)
+            data = new byte[size];
+
+        return data;
+    }
+
+    /**
+     * Reallocate.
+     *
+     * @param data Old data.
+     * @param size Size.
+     * @return New data.
+     */
+    public byte[] reallocate(byte[] data, int size) {
+        byte[] newData = new byte[size];
+
+        if (this.data == data)
+            this.data = newData;
+
+        UNSAFE.copyMemory(data, BYTE_ARR_OFF, newData, BYTE_ARR_OFF, data.length);
+
+        return newData;
+    }
+
+    /**
+     * Shrinks array size if needed.
+     */
+    public void release(byte[] data, int maxMsgSize) {
+        if (this.data != data)
+            return;
+
+        if (maxMsgSize > this.maxMsgSize)
+            this.maxMsgSize = maxMsgSize;
+
+        this.acquired = false;
+
+        long now = U.currentTimeMillis();
+
+        if (now - this.lastCheck >= CHECK_FREQ) {
+            int halfSize = data.length >> 1;
+
+            if (this.maxMsgSize < halfSize)
+                this.data = new byte[halfSize];
+
+            this.lastCheck = now;
+        }
+    }
+
+    /**
+     * @return {@code True} if acquired.
+     */
+    public boolean isAcquired() {
+        return acquired;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOffheapOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOffheapOutputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOffheapOutputStream.java
index 430a176..cadd244 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOffheapOutputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOffheapOutputStream.java
@@ -125,24 +125,69 @@ public class PortableOffheapOutputStream extends PortableAbstractOutputStream {
     }
 
     /** {@inheritDoc} */
-    @Override protected void writeShortPositioned(int pos, short val) {
+    @Override public boolean hasArray() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteByte(byte val) {
+        UNSAFE.putByte(ptr + pos++, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(short val) {
         if (!LITTLE_ENDIAN)
             val = Short.reverseBytes(val);
 
         UNSAFE.putShort(ptr + pos, val);
+
+        shift(2);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteShort(int pos, short val) {
+        if (!LITTLE_ENDIAN)
+            val = Short.reverseBytes(val);
+
+        UNSAFE.putShort(ptr + pos, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteChar(char val) {
+        if (!LITTLE_ENDIAN)
+            val = Character.reverseBytes(val);
+
+        UNSAFE.putChar(ptr + pos, val);
+
+        shift(2);
     }
 
     /** {@inheritDoc} */
-    @Override protected void writeIntPositioned(int pos, int val) {
+    @Override public void unsafeWriteInt(int val) {
         if (!LITTLE_ENDIAN)
             val = Integer.reverseBytes(val);
 
         UNSAFE.putInt(ptr + pos, val);
+
+        shift(4);
     }
 
     /** {@inheritDoc} */
-    @Override public boolean hasArray() {
-        return false;
+    @Override public void unsafeWriteInt(int pos, int val) {
+        if (!LITTLE_ENDIAN)
+            val = Integer.reverseBytes(val);
+
+        UNSAFE.putInt(ptr + pos, val);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unsafeWriteLong(long val) {
+        if (!LITTLE_ENDIAN)
+            val = Long.reverseBytes(val);
+
+        UNSAFE.putLong(ptr + pos, val);
+
+        shift(8);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOutputStream.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOutputStream.java
index 0e25b12..3a2e9e1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOutputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableOutputStream.java
@@ -170,4 +170,83 @@ public interface PortableOutputStream extends PortableStream, AutoCloseable {
      * Close the stream releasing resources.
      */
     @Override public void close();
+
+    /**
+     * Ensure capacity for unsafe writes.
+     *
+     * @param cap Capacity.
+     */
+    public void unsafeEnsure(int cap);
+
+    /**
+     * Write byte in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteByte(byte val);
+
+    /**
+     * Write boolean in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteBoolean(boolean val);
+
+    /**
+     * Write short in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteShort(short val);
+
+    /**
+     * Write short in unsafe mode.
+     *
+     * @param pos Position.
+     * @param val Value.
+     */
+    public void unsafeWriteShort(int pos, short val);
+
+    /**
+     * Write char in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteChar(char val);
+
+    /**
+     * Write int in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteInt(int val);
+
+    /**
+     * Write int in unsafe mode.
+     *
+     * @param pos Position.
+     * @param val Value.
+     */
+    public void unsafeWriteInt(int pos, int val);
+
+    /**
+     * Write long in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteLong(long val);
+
+    /**
+     * Write float in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteFloat(float val);
+
+    /**
+     * Write double in unsafe mode.
+     *
+     * @param val Value.
+     */
+    public void unsafeWriteDouble(double val);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableSimpleMemoryAllocator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableSimpleMemoryAllocator.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableSimpleMemoryAllocator.java
deleted file mode 100644
index 54d7b38..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/streams/PortableSimpleMemoryAllocator.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.portable.streams;
-
-import org.apache.ignite.internal.util.GridUnsafe;
-import sun.misc.Unsafe;
-
-/**
- * Naive implementation of portable memory allocator.
- */
-public class PortableSimpleMemoryAllocator implements PortableMemoryAllocator {
-    /** Unsafe. */
-    private static final Unsafe UNSAFE = GridUnsafe.unsafe();
-
-    /** Array offset: byte. */
-    protected static final long BYTE_ARR_OFF = UNSAFE.arrayBaseOffset(byte[].class);
-
-    /** {@inheritDoc} */
-    @Override public byte[] allocate(int size) {
-        return new byte[size];
-    }
-
-    /** {@inheritDoc} */
-    @Override public byte[] reallocate(byte[] data, int size) {
-        byte[] newData = new byte[size];
-
-        UNSAFE.copyMemory(data, BYTE_ARR_OFF, newData, BYTE_ARR_OFF, data.length);
-
-        return newData;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void release(byte[] data, int maxMsgSize) {
-        // No-op.
-    }
-
-    /** {@inheritDoc} */
-    @Override public long allocateDirect(int size) {
-        return UNSAFE.allocateMemory(size);
-    }
-
-    /** {@inheritDoc} */
-    @Override public long reallocateDirect(long addr, int size) {
-        return UNSAFE.reallocateMemory(addr, size);
-    }
-
-    /** {@inheritDoc} */
-    @Override public void releaseDirect(long addr) {
-        UNSAFE.freeMemory(addr);
-    }
-}
\ No newline at end of file


[5/5] ignite git commit: IGNITE-1917: Binary protocol performance optimizations.

Posted by vo...@apache.org.
IGNITE-1917: Binary protocol performance optimizations.


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

Branch: refs/heads/ignite-1282
Commit: 4a1af37e39783d57b924138fb1e4aeddc137fc8a
Parents: 5ea0625
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Fri Nov 20 09:29:19 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Fri Nov 20 09:29:19 2015 +0300

----------------------------------------------------------------------
 .../apache/ignite/internal/IgniteKernal.java    |    5 +-
 .../internal/portable/BinaryEnumCache.java      |   69 +
 .../internal/portable/BinaryFieldAccessor.java  |  805 ++++++++
 .../portable/BinaryMetadataCollector.java       |   66 +-
 .../internal/portable/BinaryObjectEx.java       |    8 +-
 .../internal/portable/BinaryObjectImpl.java     |   47 +-
 .../portable/BinaryObjectOffheapImpl.java       |  105 +-
 .../internal/portable/BinaryReaderExImpl.java   | 1823 +++++++++---------
 .../internal/portable/BinaryReaderHandles.java  |  108 ++
 .../portable/BinaryThreadLocalContext.java      |   69 +
 .../internal/portable/BinaryTypeImpl.java       |    1 +
 .../internal/portable/BinaryWriteMode.java      |  178 ++
 .../internal/portable/BinaryWriterExImpl.java   |  866 ++++-----
 .../internal/portable/BinaryWriterHandles.java  |  101 +
 .../portable/BinaryWriterSchemaHolder.java      |  148 ++
 .../portable/GridPortableMarshaller.java        |   11 +-
 .../portable/PortableClassDescriptor.java       |  747 +------
 .../internal/portable/PortableContext.java      |    8 +-
 .../portable/PortableReaderContext.java         |  105 -
 .../internal/portable/PortableSchema.java       |  405 ++--
 .../PortableThreadLocalMemoryAllocator.java     |  162 --
 .../ignite/internal/portable/PortableUtils.java |  120 +-
 .../builder/BinaryObjectBuilderImpl.java        |    8 +-
 .../portable/builder/PortableBuilderReader.java |   54 +-
 .../streams/PortableAbstractOutputStream.java   |   40 +-
 .../streams/PortableHeapInputStream.java        |   17 +
 .../streams/PortableHeapOutputStream.java       |  100 +-
 .../streams/PortableMemoryAllocator.java        |   67 +-
 .../streams/PortableMemoryAllocatorChunk.java   |  117 ++
 .../streams/PortableOffheapOutputStream.java    |   53 +-
 .../portable/streams/PortableOutputStream.java  |   79 +
 .../streams/PortableSimpleMemoryAllocator.java  |   66 -
 .../PlatformBigEndianOutputStreamImpl.java      |   30 +
 .../memory/PlatformOutputStreamImpl.java        |   63 +
 .../ignite/internal/util/GridEnumCache.java     |   56 -
 .../portable/BinaryMarshallerSelfTest.java      |   30 +-
 .../testframework/junits/GridAbstractTest.java  |    4 +-
 .../Cache/Query/CacheQueriesTest.cs             |    2 -
 38 files changed, 3832 insertions(+), 2911 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 2b6eaad..2e8520e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -102,7 +102,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.GridCacheUtilityKey;
 import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
-import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessor;
 import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
 import org.apache.ignite.internal.processors.clock.GridClockSyncProcessor;
@@ -132,7 +131,7 @@ import org.apache.ignite.internal.processors.service.GridServiceProcessor;
 import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor;
 import org.apache.ignite.internal.processors.task.GridTaskProcessor;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
-import org.apache.ignite.internal.util.GridEnumCache;
+import org.apache.ignite.internal.portable.BinaryEnumCache;
 import org.apache.ignite.internal.util.GridTimerTask;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -1941,7 +1940,7 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
             // Clean internal class/classloader caches to avoid stopped contexts held in memory.
             U.clearClassCache();
             MarshallerExclusions.clearCache();
-            GridEnumCache.clear();
+            BinaryEnumCache.clear();
 
             gw.writeLock();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumCache.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumCache.java
new file mode 100644
index 0000000..fc042e5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumCache.java
@@ -0,0 +1,69 @@
+/*
+ * 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.portable;
+
+import org.apache.ignite.binary.BinaryObjectException;
+import org.jsr166.ConcurrentHashMap8;
+
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Cache for enum constants.
+ */
+public class BinaryEnumCache {
+    /** Cache for enum constants. */
+    private static final ConcurrentMap<Class<?>, Object[]> ENUM_CACHE = new ConcurrentHashMap8<>();
+
+    /**
+     * Get value for the given class and ordinal.
+     *
+     * @param cls Class.
+     * @param ord Ordinal.
+     * @return Value.
+     * @throws BinaryObjectException In case of invalid ordinal.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T get(Class<?> cls, int ord) throws BinaryObjectException {
+        assert cls != null;
+
+        if (ord >= 0) {
+            Object[] vals = ENUM_CACHE.get(cls);
+
+            if (vals == null) {
+                vals = cls.getEnumConstants();
+
+                ENUM_CACHE.putIfAbsent(cls, vals);
+            }
+
+            if (ord < vals.length)
+                return (T) vals[ord];
+            else
+                throw new BinaryObjectException("Failed to get enum value for ordinal (do you have correct class " +
+                    "version?) [cls=" + cls.getName() + ", ordinal=" + ord + ", totalValues=" + vals.length + ']');
+        }
+        else
+            return null;
+    }
+
+    /**
+     * Clears cache.
+     */
+    public static void clear() {
+        ENUM_CACHE.clear();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java
new file mode 100644
index 0000000..0eda375
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldAccessor.java
@@ -0,0 +1,805 @@
+/*
+ * 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.portable;
+
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.internal.util.GridUnsafe;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Field accessor to speedup access.
+ */
+public abstract class BinaryFieldAccessor {
+    /** Field ID. */
+    protected final int id;
+
+    /** Mode. */
+    protected final BinaryWriteMode mode;
+
+    /**
+     * Create accessor for the field.
+     *
+     * @param field Field.
+     * @param id FIeld ID.
+     * @return Accessor.
+     */
+    public static BinaryFieldAccessor create(Field field, int id) {
+        BinaryWriteMode mode = PortableUtils.mode(field.getType());
+
+        switch (mode) {
+            case P_BYTE:
+                return new BytePrimitiveAccessor(field, id);
+
+            case P_BOOLEAN:
+                return new BooleanPrimitiveAccessor(field, id);
+
+            case P_SHORT:
+                return new ShortPrimitiveAccessor(field, id);
+
+            case P_CHAR:
+                return new CharPrimitiveAccessor(field, id);
+
+            case P_INT:
+                return new IntPrimitiveAccessor(field, id);
+
+            case P_LONG:
+                return new LongPrimitiveAccessor(field, id);
+
+            case P_FLOAT:
+                return new FloatPrimitiveAccessor(field, id);
+
+            case P_DOUBLE:
+                return new DoublePrimitiveAccessor(field, id);
+
+            default:
+                return new DefaultAccessor(field, id, mode);
+        }
+    }
+
+    /**
+     * Protected constructor.
+     *
+     * @param id Field ID.
+     * @param mode Mode;
+     */
+    protected BinaryFieldAccessor(int id, BinaryWriteMode mode) {
+        assert id != 0;
+        assert mode != null;
+
+        this.id = id;
+        this.mode = mode;
+    }
+
+    /**
+     * Get mode.
+     *
+     * @return Mode.
+     */
+    public BinaryWriteMode mode() {
+        return mode;
+    }
+
+    /**
+     * Write field.
+     *
+     * @param obj Object.
+     * @param writer Writer.
+     * @throws BinaryObjectException If failed.
+     */
+    public abstract void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException;
+
+    /**
+     * Read field.
+     *
+     * @param obj Object.
+     * @param reader Reader.
+     * @throws BinaryObjectException If failed.
+     */
+    public abstract void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException;
+
+    /**
+     * Base primitive field accessor.
+     */
+    private static abstract class AbstractPrimitiveAccessor extends BinaryFieldAccessor {
+        /** Unsafe instance. */
+        protected static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+        /** Offset. */
+        protected final long offset;
+
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         * @param id Field ID.
+         * @param mode Mode.
+         */
+        protected AbstractPrimitiveAccessor(Field field, int id, BinaryWriteMode mode) {
+            super(id, mode);
+
+            assert field != null;
+
+            offset = UNSAFE.objectFieldOffset(field);
+        }
+    }
+
+    /**
+     * Byte field accessor.
+     */
+    private static class BytePrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public BytePrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_BYTE);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            byte val = UNSAFE.getByte(obj, offset);
+
+            writer.writeByteFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            byte val = reader.readByte(id);
+
+            UNSAFE.putByte(obj, offset, val);
+        }
+    }
+
+    /**
+     * Boolean field accessor.
+     */
+    private static class BooleanPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public BooleanPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_BOOLEAN);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            boolean val = UNSAFE.getBoolean(obj, offset);
+
+            writer.writeBooleanFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            boolean val = reader.readBoolean(id);
+
+            UNSAFE.putBoolean(obj, offset, val);
+        }
+    }
+
+    /**
+     * Short field accessor.
+     */
+    private static class ShortPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public ShortPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_SHORT);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            short val = UNSAFE.getShort(obj, offset);
+
+            writer.writeShortFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            short val = reader.readShort(id);
+
+            UNSAFE.putShort(obj, offset, val);
+        }
+    }
+
+    /**
+     * Char field accessor.
+     */
+    private static class CharPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public CharPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_CHAR);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            char val = UNSAFE.getChar(obj, offset);
+
+            writer.writeCharFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            char val = reader.readChar(id);
+
+            UNSAFE.putChar(obj, offset, val);
+        }
+    }
+
+    /**
+     * Int field accessor.
+     */
+    private static class IntPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public IntPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_INT);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            int val = UNSAFE.getInt(obj, offset);
+
+            writer.writeIntFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            int val = reader.readInt(id);
+
+            UNSAFE.putInt(obj, offset, val);
+        }
+    }
+
+    /**
+     * Long field accessor.
+     */
+    private static class LongPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public LongPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_LONG);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            long val = UNSAFE.getLong(obj, offset);
+
+            writer.writeLongFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            long val = reader.readLong(id);
+
+            UNSAFE.putLong(obj, offset, val);
+        }
+    }
+
+    /**
+     * Float field accessor.
+     */
+    private static class FloatPrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public FloatPrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_FLOAT);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            float val = UNSAFE.getFloat(obj, offset);
+
+            writer.writeFloatFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            float val = reader.readFloat(id);
+
+            UNSAFE.putFloat(obj, offset, val);
+        }
+    }
+
+    /**
+     * Double field accessor.
+     */
+    private static class DoublePrimitiveAccessor extends AbstractPrimitiveAccessor {
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         */
+        public DoublePrimitiveAccessor(Field field, int id) {
+            super(field, id, BinaryWriteMode.P_DOUBLE);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            double val = UNSAFE.getDouble(obj, offset);
+
+            writer.writeDoubleFieldPrimitive(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            double val = reader.readDouble(id);
+
+            UNSAFE.putDouble(obj, offset, val);
+        }
+    }
+
+    /**
+     * Default accessor.
+     */
+    private static class DefaultAccessor extends BinaryFieldAccessor {
+        /** Target field. */
+        private final Field field;
+
+        /**
+         * Constructor.
+         *
+         * @param field Field.
+         * @param id Field ID.
+         * @param mode Mode.
+         */
+        public DefaultAccessor(Field field, int id, BinaryWriteMode mode) {
+            super(id, mode);
+
+            assert field != null;
+
+            this.field = field;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Object obj, BinaryWriterExImpl writer) throws BinaryObjectException {
+            assert obj != null;
+            assert writer != null;
+
+            writer.writeFieldIdNoSchemaUpdate(id);
+
+            Object val;
+
+            try {
+                val = field.get(obj);
+            }
+            catch (IllegalAccessException e) {
+                throw new BinaryObjectException("Failed to get value for field: " + field, e);
+            }
+
+            switch (mode) {
+                case BYTE:
+                    writer.writeByteField((Byte) val);
+
+                    break;
+
+                case SHORT:
+                    writer.writeShortField((Short) val);
+
+                    break;
+
+                case INT:
+                    writer.writeIntField((Integer) val);
+
+                    break;
+
+                case LONG:
+                    writer.writeLongField((Long)val);
+
+                    break;
+
+                case FLOAT:
+                    writer.writeFloatField((Float)val);
+
+                    break;
+
+                case DOUBLE:
+                    writer.writeDoubleField((Double)val);
+
+                    break;
+
+                case CHAR:
+                    writer.writeCharField((Character)val);
+
+                    break;
+
+                case BOOLEAN:
+                    writer.writeBooleanField((Boolean)val);
+
+                    break;
+
+                case DECIMAL:
+                    writer.writeDecimalField((BigDecimal)val);
+
+                    break;
+
+                case STRING:
+                    writer.writeStringField((String)val);
+
+                    break;
+
+                case UUID:
+                    writer.writeUuidField((UUID)val);
+
+                    break;
+
+                case DATE:
+                    writer.writeDateField((Date)val);
+
+                    break;
+
+                case TIMESTAMP:
+                    writer.writeTimestampField((Timestamp)val);
+
+                    break;
+
+                case BYTE_ARR:
+                    writer.writeByteArrayField((byte[])val);
+
+                    break;
+
+                case SHORT_ARR:
+                    writer.writeShortArrayField((short[])val);
+
+                    break;
+
+                case INT_ARR:
+                    writer.writeIntArrayField((int[])val);
+
+                    break;
+
+                case LONG_ARR:
+                    writer.writeLongArrayField((long[])val);
+
+                    break;
+
+                case FLOAT_ARR:
+                    writer.writeFloatArrayField((float[])val);
+
+                    break;
+
+                case DOUBLE_ARR:
+                    writer.writeDoubleArrayField((double[])val);
+
+                    break;
+
+                case CHAR_ARR:
+                    writer.writeCharArrayField((char[])val);
+
+                    break;
+
+                case BOOLEAN_ARR:
+                    writer.writeBooleanArrayField((boolean[])val);
+
+                    break;
+
+                case DECIMAL_ARR:
+                    writer.writeDecimalArrayField((BigDecimal[])val);
+
+                    break;
+
+                case STRING_ARR:
+                    writer.writeStringArrayField((String[])val);
+
+                    break;
+
+                case UUID_ARR:
+                    writer.writeUuidArrayField((UUID[])val);
+
+                    break;
+
+                case DATE_ARR:
+                    writer.writeDateArrayField((Date[])val);
+
+                    break;
+
+                case TIMESTAMP_ARR:
+                    writer.writeTimestampArrayField((Timestamp[])val);
+
+                    break;
+
+                case OBJECT_ARR:
+                    writer.writeObjectArrayField((Object[])val);
+
+                    break;
+
+                case COL:
+                    writer.writeCollectionField((Collection<?>)val);
+
+                    break;
+
+                case MAP:
+                    writer.writeMapField((Map<?, ?>)val);
+
+                    break;
+
+                case MAP_ENTRY:
+                    writer.writeMapEntryField((Map.Entry<?, ?>)val);
+
+                    break;
+
+                case PORTABLE_OBJ:
+                    writer.writePortableObjectField((BinaryObjectImpl)val);
+
+                    break;
+
+                case ENUM:
+                    writer.writeEnumField((Enum<?>)val);
+
+                    break;
+
+                case ENUM_ARR:
+                    writer.writeEnumArrayField((Object[])val);
+
+                    break;
+
+                case PORTABLE:
+                case EXTERNALIZABLE:
+                case OBJECT:
+                    writer.writeObjectField(val);
+
+                    break;
+
+                case CLASS:
+                    writer.writeClassField((Class)val);
+
+                    break;
+
+                default:
+                    assert false : "Invalid mode: " + mode;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void read(Object obj, BinaryReaderExImpl reader) throws BinaryObjectException {
+            Object val = null;
+
+            switch (mode) {
+                case BYTE:
+                    val = reader.readByteNullable(id);
+
+                    break;
+
+                case SHORT:
+                    val = reader.readShortNullable(id);
+
+                    break;
+
+                case INT:
+                    val = reader.readIntNullable(id);
+
+                    break;
+
+                case LONG:
+                    val = reader.readLongNullable(id);
+
+                    break;
+
+                case FLOAT:
+                    val = reader.readFloatNullable(id);
+
+                    break;
+
+                case DOUBLE:
+                    val = reader.readDoubleNullable(id);
+
+                    break;
+
+                case CHAR:
+                    val = reader.readCharNullable(id);
+
+                    break;
+
+                case BOOLEAN:
+                    val = reader.readBooleanNullable(id);
+
+                    break;
+
+                case DECIMAL:
+                    val = reader.readDecimal(id);
+
+                    break;
+
+                case STRING:
+                    val = reader.readString(id);
+
+                    break;
+
+                case UUID:
+                    val = reader.readUuid(id);
+
+                    break;
+
+                case DATE:
+                    val = reader.readDate(id);
+
+                    break;
+
+                case TIMESTAMP:
+                    val = reader.readTimestamp(id);
+
+                    break;
+
+                case BYTE_ARR:
+                    val = reader.readByteArray(id);
+
+                    break;
+
+                case SHORT_ARR:
+                    val = reader.readShortArray(id);
+
+                    break;
+
+                case INT_ARR:
+                    val = reader.readIntArray(id);
+
+                    break;
+
+                case LONG_ARR:
+                    val = reader.readLongArray(id);
+
+                    break;
+
+                case FLOAT_ARR:
+                    val = reader.readFloatArray(id);
+
+                    break;
+
+                case DOUBLE_ARR:
+                    val = reader.readDoubleArray(id);
+
+                    break;
+
+                case CHAR_ARR:
+                    val = reader.readCharArray(id);
+
+                    break;
+
+                case BOOLEAN_ARR:
+                    val = reader.readBooleanArray(id);
+
+                    break;
+
+                case DECIMAL_ARR:
+                    val = reader.readDecimalArray(id);
+
+                    break;
+
+                case STRING_ARR:
+                    val = reader.readStringArray(id);
+
+                    break;
+
+                case UUID_ARR:
+                    val = reader.readUuidArray(id);
+
+                    break;
+
+                case DATE_ARR:
+                    val = reader.readDateArray(id);
+
+                    break;
+
+                case TIMESTAMP_ARR:
+                    val = reader.readTimestampArray(id);
+
+                    break;
+
+                case OBJECT_ARR:
+                    val = reader.readObjectArray(id);
+
+                    break;
+
+                case COL:
+                    val = reader.readCollection(id, null);
+
+                    break;
+
+                case MAP:
+                    val = reader.readMap(id, null);
+
+                    break;
+
+                case MAP_ENTRY:
+                    val = reader.readMapEntry(id);
+
+                    break;
+
+                case PORTABLE_OBJ:
+                    val = reader.readPortableObject(id);
+
+                    break;
+
+                case ENUM:
+                    val = reader.readEnum(id, field.getType());
+
+                    break;
+
+                case ENUM_ARR:
+                    val = reader.readEnumArray(id, field.getType().getComponentType());
+
+                    break;
+
+                case PORTABLE:
+                case EXTERNALIZABLE:
+                case OBJECT:
+                    val = reader.readObject(id);
+
+                    break;
+
+                case CLASS:
+                    val = reader.readClass(id);
+
+                    break;
+
+                default:
+                    assert false : "Invalid mode: " + mode;
+            }
+
+            try {
+                if (val != null || !field.getType().isPrimitive())
+                    field.set(obj, val);
+            }
+            catch (IllegalAccessException e) {
+                throw new BinaryObjectException("Failed to set value for field: " + field, e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadataCollector.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadataCollector.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadataCollector.java
index 28eb1d0..6ad0ad1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadataCollector.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadataCollector.java
@@ -82,163 +82,163 @@ class BinaryMetadataCollector implements BinaryWriter {
 
     /** {@inheritDoc} */
     @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.BYTE);
+        add(fieldName, BinaryWriteMode.BYTE);
     }
 
     /** {@inheritDoc} */
     @Override public void writeShort(String fieldName, short val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.SHORT);
+        add(fieldName, BinaryWriteMode.SHORT);
     }
 
     /** {@inheritDoc} */
     @Override public void writeInt(String fieldName, int val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.INT);
+        add(fieldName, BinaryWriteMode.INT);
     }
 
     /** {@inheritDoc} */
     @Override public void writeLong(String fieldName, long val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.LONG);
+        add(fieldName, BinaryWriteMode.LONG);
     }
 
     /** {@inheritDoc} */
     @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.FLOAT);
+        add(fieldName, BinaryWriteMode.FLOAT);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DOUBLE);
+        add(fieldName, BinaryWriteMode.DOUBLE);
     }
 
     /** {@inheritDoc} */
     @Override public void writeChar(String fieldName, char val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.CHAR);
+        add(fieldName, BinaryWriteMode.CHAR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.BOOLEAN);
+        add(fieldName, BinaryWriteMode.BOOLEAN);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DECIMAL);
+        add(fieldName, BinaryWriteMode.DECIMAL);
     }
 
     /** {@inheritDoc} */
     @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.STRING);
+        add(fieldName, BinaryWriteMode.STRING);
     }
 
     /** {@inheritDoc} */
     @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.UUID);
+        add(fieldName, BinaryWriteMode.UUID);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DATE);
+        add(fieldName, BinaryWriteMode.DATE);
     }
 
     /** {@inheritDoc} */
     @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.TIMESTAMP);
+        add(fieldName, BinaryWriteMode.TIMESTAMP);
     }
 
     /** {@inheritDoc} */
     @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.ENUM);
+        add(fieldName, BinaryWriteMode.ENUM);
     }
 
     /** {@inheritDoc} */
     @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.ENUM_ARR);
+        add(fieldName, BinaryWriteMode.ENUM_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.OBJECT);
+        add(fieldName, BinaryWriteMode.OBJECT);
     }
 
     /** {@inheritDoc} */
     @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.BYTE_ARR);
+        add(fieldName, BinaryWriteMode.BYTE_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.SHORT_ARR);
+        add(fieldName, BinaryWriteMode.SHORT_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.INT_ARR);
+        add(fieldName, BinaryWriteMode.INT_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.LONG_ARR);
+        add(fieldName, BinaryWriteMode.LONG_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.FLOAT_ARR);
+        add(fieldName, BinaryWriteMode.FLOAT_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DOUBLE_ARR);
+        add(fieldName, BinaryWriteMode.DOUBLE_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.CHAR_ARR);
+        add(fieldName, BinaryWriteMode.CHAR_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.BOOLEAN_ARR);
+        add(fieldName, BinaryWriteMode.BOOLEAN_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DECIMAL_ARR);
+        add(fieldName, BinaryWriteMode.DECIMAL_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeStringArray(String fieldName, @Nullable String[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.STRING_ARR);
+        add(fieldName, BinaryWriteMode.STRING_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.UUID_ARR);
+        add(fieldName, BinaryWriteMode.UUID_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.DATE_ARR);
+        add(fieldName, BinaryWriteMode.DATE_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.TIMESTAMP_ARR);
+        add(fieldName, BinaryWriteMode.TIMESTAMP_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.OBJECT_ARR);
+        add(fieldName, BinaryWriteMode.OBJECT_ARR);
     }
 
     /** {@inheritDoc} */
     @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col)
         throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.COL);
+        add(fieldName, BinaryWriteMode.COL);
     }
 
     /** {@inheritDoc} */
     @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws BinaryObjectException {
-        add(fieldName, PortableClassDescriptor.Mode.MAP);
+        add(fieldName, BinaryWriteMode.MAP);
     }
 
     /** {@inheritDoc} */
@@ -257,7 +257,7 @@ class BinaryMetadataCollector implements BinaryWriter {
      * @param mode Field mode.
      * @throws BinaryObjectException In case of error.
      */
-    private void add(String name, PortableClassDescriptor.Mode mode) throws BinaryObjectException {
+    private void add(String name, BinaryWriteMode mode) throws BinaryObjectException {
         assert name != null;
 
         int fieldTypeId = mode.typeId();

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
index 6902675..597fad5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
@@ -79,7 +79,7 @@ public abstract class BinaryObjectEx implements BinaryObject {
      * @param fieldName Field name.
      * @return Field value.
      */
-    @Nullable protected abstract <F> F field(PortableReaderContext ctx, String fieldName);
+    @Nullable protected abstract <F> F field(BinaryReaderHandles ctx, String fieldName);
 
     /**
      * Get schema ID.
@@ -157,7 +157,7 @@ public abstract class BinaryObjectEx implements BinaryObject {
      * @param handles Handles for already traversed objects.
      * @return String representation.
      */
-    private String toString(PortableReaderContext ctx, IdentityHashMap<BinaryObject, Integer> handles) {
+    private String toString(BinaryReaderHandles ctx, IdentityHashMap<BinaryObject, Integer> handles) {
         int idHash = System.identityHashCode(this);
 
         BinaryType meta;
@@ -232,9 +232,9 @@ public abstract class BinaryObjectEx implements BinaryObject {
     /** {@inheritDoc} */
     @Override public String toString() {
         try {
-            PortableReaderContext ctx = new PortableReaderContext();
+            BinaryReaderHandles ctx = new BinaryReaderHandles();
 
-            ctx.setPortableHandler(start(), this);
+            ctx.put(start(), this);
 
             return toString(ctx, new IdentityHashMap<BinaryObject, Integer>());
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
index d9339f8..7ab9497 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
@@ -25,7 +25,6 @@ import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
-import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
@@ -33,7 +32,6 @@ import org.apache.ignite.plugin.extensions.communication.MessageWriter;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.binary.BinaryObject;
-import org.apache.ignite.binary.BinaryField;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.Externalizable;
@@ -257,17 +255,13 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Nullable @Override public <F> F field(String fieldName) throws BinaryObjectException {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
-
-        return (F)reader.unmarshalField(fieldName);
+        return (F)newReader().unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Nullable @Override public <F> F field(int fieldId) throws BinaryObjectException {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
-
-        return (F)reader.unmarshalField(fieldId);
+        return (F)newReader().unmarshalField(fieldId);
     }
 
     /** {@inheritDoc} */
@@ -400,11 +394,13 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
 
                 break;
 
-            default: {
-                BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
+            default:
+                BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, fieldPos),
+                    null, new BinaryReaderHandles());
 
-                val = reader.unmarshalFieldByAbsolutePosition(fieldPos);
-            }
+                val = reader.unmarshal();
+
+                break;
         }
 
         return (F)val;
@@ -412,21 +408,15 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
-    @Nullable @Override protected <F> F field(PortableReaderContext rCtx, String fieldName) {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableHeapInputStream(arr),
-            start,
-            null,
-            rCtx);
+    @Nullable @Override protected <F> F field(BinaryReaderHandles rCtx, String fieldName) {
+        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, start), null, rCtx);
 
         return (F)reader.unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public boolean hasField(String fieldName) {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
-
-        return reader.hasField(fieldName);
+        return newReader().hasField(fieldName);
     }
 
     /** {@inheritDoc} */
@@ -458,9 +448,7 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
 
     /** {@inheritDoc} */
     @Override protected PortableSchema createSchema() {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
-
-        return reader.getOrCreateSchema();
+        return newReader().getOrCreateSchema();
     }
 
     /** {@inheritDoc} */
@@ -569,7 +557,7 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
      */
     private Object deserializeValue() {
         // TODO: IGNITE-1272 - Deserialize with proper class loader.
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, start, null);
+        BinaryReaderExImpl reader = newReader();
 
         Object obj0 = reader.deserialize();
 
@@ -582,4 +570,13 @@ public final class BinaryObjectImpl extends BinaryObjectEx implements Externaliz
 
         return obj0;
     }
+
+    /**
+     * Create new reader for this object.
+     *
+     * @return Reader.
+     */
+    private BinaryReaderExImpl newReader() {
+        return new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, start), null, new BinaryReaderHandles());
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
index a71c98a..6f9190a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
@@ -17,18 +17,11 @@
 
 package org.apache.ignite.internal.portable;
 
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.sql.Timestamp;
-import java.util.Date;
-import java.util.UUID;
-
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.binary.BinaryField;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.internal.portable.streams.PortableOffheapInputStream;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
@@ -37,13 +30,20 @@ import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
-import org.apache.ignite.binary.BinaryObjectException;
-import org.apache.ignite.binary.BinaryType;
-import org.apache.ignite.binary.BinaryObject;
-import org.apache.ignite.binary.BinaryField;
 import org.jetbrains.annotations.Nullable;
 import sun.misc.Unsafe;
 
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.UUID;
+
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE;
@@ -131,12 +131,7 @@ public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externali
 
     /** {@inheritDoc} */
     @Override protected PortableSchema createSchema() {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
-
-        return reader.getOrCreateSchema();
+        return newReader().getOrCreateSchema();
     }
 
     /** {@inheritDoc} */
@@ -170,23 +165,13 @@ public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externali
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Nullable @Override public <F> F field(String fieldName) throws BinaryObjectException {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
-
-        return (F)reader.unmarshalField(fieldName);
+        return (F)newReader().unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Nullable @Override public <F> F field(int fieldId) throws BinaryObjectException {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
-
-        return (F)reader.unmarshalField(fieldId);
+        return (F)newReader().unmarshalField(fieldId);
     }
 
     /** {@inheritDoc} */
@@ -320,14 +305,16 @@ public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externali
 
                 break;
 
-            default: {
-                BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-                    new PortableOffheapInputStream(ptr, size, false),
-                    start,
-                    null);
+            default:
+                PortableOffheapInputStream stream = new PortableOffheapInputStream(ptr, size, false);
 
-                val = reader.unmarshalFieldByAbsolutePosition(fieldPos);
-            }
+                stream.position(fieldPos);
+
+                BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, stream, null, new BinaryReaderHandles());
+
+                val = reader.unmarshal();
+
+                break;
         }
 
         return (F)val;
@@ -335,24 +322,19 @@ public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externali
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
-    @Nullable @Override protected <F> F field(PortableReaderContext rCtx, String fieldName) {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null,
-            rCtx);
+    @Nullable @Override protected <F> F field(BinaryReaderHandles rCtx, String fieldName) {
+        PortableOffheapInputStream stream = new PortableOffheapInputStream(ptr, size, false);
+
+        stream.position(start);
+
+        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, stream, null, rCtx);
 
         return (F)reader.unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public boolean hasField(String fieldName) {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
-
-        return reader.hasField(fieldName);
+        return newReader().hasField(fieldName);
     }
 
     /** {@inheritDoc} */
@@ -438,12 +420,19 @@ public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externali
      */
     private Object deserializeValue() {
         // TODO: IGNITE-1272 - Deserialize with proper class loader.
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(
-            ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
+        return newReader().deserialize();
+    }
+
+    /**
+     * Create new reader for this object.
+     *
+     * @return Reader.
+     */
+    private BinaryReaderExImpl newReader() {
+        PortableOffheapInputStream stream = new PortableOffheapInputStream(ptr, size, false);
+
+        stream.position(start);
 
-        return reader.deserialize();
+        return new BinaryReaderExImpl(ctx, stream, null, new BinaryReaderHandles());
     }
 }
\ No newline at end of file


[3/5] ignite git commit: IGNITE-1917: Binary protocol performance optimizations.

Posted by vo...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderHandles.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderHandles.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderHandles.java
new file mode 100644
index 0000000..0024db0
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderHandles.java
@@ -0,0 +1,108 @@
+/*
+ * 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.portable;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Reader handles.
+ */
+public class BinaryReaderHandles {
+    /** Mode: empty. */
+    private static final int MODE_EMPTY = 0;
+
+    /** Mode: single object. */
+    private static final int MODE_SINGLE = 1;
+
+    /** Mode: multiple objects. */
+    private static final int MODE_MULTIPLE = 2;
+
+    /** Position.  */
+    private int singlePos;
+
+    /** Data. This is either an object or a map. */
+    private Object data;
+
+    /** Mode. */
+    private int mode = MODE_EMPTY;
+
+    /**
+     * Get object by position.
+     *
+     * @param pos Position.
+     * @return Object.
+     */
+    @SuppressWarnings("unchecked")
+    public @Nullable <T> T get(int pos) {
+        switch (mode) {
+            case MODE_EMPTY:
+                return null;
+
+            case MODE_SINGLE:
+                return (T)data;
+
+            default:
+                assert mode == MODE_MULTIPLE;
+
+                return (T)((Map<Integer, Object>)data).get(pos);
+        }
+    }
+
+    /**
+     * Put object to registry and return previous position (if any).
+     *
+     * @param pos Position.
+     * @param obj Object.
+     */
+    @SuppressWarnings("unchecked")
+    public void put(int pos, Object obj) {
+        assert pos >= 0;
+        assert obj != null;
+
+        switch (mode) {
+            case MODE_EMPTY:
+                this.singlePos = pos;
+                this.data = obj;
+                this.mode = MODE_SINGLE;
+
+                break;
+
+            case MODE_SINGLE:
+                Map<Integer, Object> newData = new HashMap(3, 1.0f);
+
+                newData.put(singlePos, data);
+                newData.put(pos, obj);
+
+                this.singlePos = -1;
+                this.data = newData;
+                this.mode = MODE_MULTIPLE;
+
+                break;
+
+            default:
+                assert mode == MODE_MULTIPLE;
+
+                Map<Integer, Object> data0 = (Map<Integer, Object>)data;
+
+                data0.put(pos, obj);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryThreadLocalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryThreadLocalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryThreadLocalContext.java
new file mode 100644
index 0000000..c6a7fc3
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryThreadLocalContext.java
@@ -0,0 +1,69 @@
+/*
+ * 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.portable;
+
+import org.apache.ignite.internal.portable.streams.PortableMemoryAllocator;
+import org.apache.ignite.internal.portable.streams.PortableMemoryAllocatorChunk;
+
+/**
+ * Contains thread-local data for binary marshalling.
+ */
+public class BinaryThreadLocalContext {
+    /** Thread-local instance. */
+    private static final ThreadLocal<BinaryThreadLocalContext> CTX = new ThreadLocal<BinaryThreadLocalContext>() {
+        @Override protected BinaryThreadLocalContext initialValue() {
+            return new BinaryThreadLocalContext();
+        }
+    };
+
+    /** Memory chunk. */
+    private final PortableMemoryAllocatorChunk chunk = PortableMemoryAllocator.INSTANCE.chunk();
+
+    /** Schema holder. */
+    private final BinaryWriterSchemaHolder schema = new BinaryWriterSchemaHolder();
+
+    /**
+     * Get current context.
+     *
+     * @return Context.
+     */
+    public static BinaryThreadLocalContext get() {
+        return CTX.get();
+    }
+
+    /**
+     * Private constructor.
+     */
+    private BinaryThreadLocalContext() {
+        // No-op.
+    }
+
+    /**
+     * @return Memory chunk.
+     */
+    public PortableMemoryAllocatorChunk chunk() {
+        return chunk;
+    }
+
+    /**
+     * @return Schema holder.
+     */
+    public BinaryWriterSchemaHolder schemaHolder() {
+        return schema;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
index 60c135d..2630a40 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
@@ -71,6 +71,7 @@ public class BinaryTypeImpl implements BinaryType {
     public PortableContext context() {
         return ctx;
     }
+
     /**
      * @return Metadata.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
new file mode 100644
index 0000000..a26b741
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
@@ -0,0 +1,178 @@
+/*
+ * 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.portable;
+
+/**
+ * Various write modes for binary objects.
+ */
+public enum BinaryWriteMode {
+    /** Primitive byte. */
+    P_BYTE(GridPortableMarshaller.BYTE),
+
+    /** Primitive boolean. */
+    P_BOOLEAN(GridPortableMarshaller.BOOLEAN),
+
+    /** Primitive short. */
+    P_SHORT(GridPortableMarshaller.SHORT),
+
+    /** Primitive char. */
+    P_CHAR(GridPortableMarshaller.CHAR),
+
+    /** Primitive int. */
+    P_INT(GridPortableMarshaller.INT),
+
+    /** Primitive long. */
+    P_LONG(GridPortableMarshaller.LONG),
+
+    /** Primitive float. */
+    P_FLOAT(GridPortableMarshaller.FLOAT),
+
+    /** Primitive int. */
+    P_DOUBLE(GridPortableMarshaller.DOUBLE),
+
+    /** */
+    BYTE(GridPortableMarshaller.BYTE),
+
+    /** */
+    SHORT(GridPortableMarshaller.SHORT),
+
+    /** */
+    INT(GridPortableMarshaller.INT),
+
+    /** */
+    LONG(GridPortableMarshaller.LONG),
+
+    /** */
+    FLOAT(GridPortableMarshaller.FLOAT),
+
+    /** */
+    DOUBLE(GridPortableMarshaller.DOUBLE),
+
+    /** */
+    CHAR(GridPortableMarshaller.CHAR),
+
+    /** */
+    BOOLEAN(GridPortableMarshaller.BOOLEAN),
+
+    /** */
+    DECIMAL(GridPortableMarshaller.DECIMAL),
+
+    /** */
+    STRING(GridPortableMarshaller.STRING),
+
+    /** */
+    UUID(GridPortableMarshaller.UUID),
+
+    /** */
+    DATE(GridPortableMarshaller.DATE),
+
+    /** */
+    TIMESTAMP(GridPortableMarshaller.TIMESTAMP),
+
+    /** */
+    BYTE_ARR(GridPortableMarshaller.BYTE_ARR),
+
+    /** */
+    SHORT_ARR(GridPortableMarshaller.SHORT_ARR),
+
+    /** */
+    INT_ARR(GridPortableMarshaller.INT_ARR),
+
+    /** */
+    LONG_ARR(GridPortableMarshaller.LONG_ARR),
+
+    /** */
+    FLOAT_ARR(GridPortableMarshaller.FLOAT_ARR),
+
+    /** */
+    DOUBLE_ARR(GridPortableMarshaller.DOUBLE_ARR),
+
+    /** */
+    CHAR_ARR(GridPortableMarshaller.CHAR_ARR),
+
+    /** */
+    BOOLEAN_ARR(GridPortableMarshaller.BOOLEAN_ARR),
+
+    /** */
+    DECIMAL_ARR(GridPortableMarshaller.DECIMAL_ARR),
+
+    /** */
+    STRING_ARR(GridPortableMarshaller.STRING_ARR),
+
+    /** */
+    UUID_ARR(GridPortableMarshaller.UUID_ARR),
+
+    /** */
+    DATE_ARR(GridPortableMarshaller.DATE_ARR),
+
+    /** */
+    TIMESTAMP_ARR(GridPortableMarshaller.TIMESTAMP_ARR),
+
+    /** */
+    OBJECT_ARR(GridPortableMarshaller.OBJ_ARR),
+
+    /** */
+    COL(GridPortableMarshaller.COL),
+
+    /** */
+    MAP(GridPortableMarshaller.MAP),
+
+    /** */
+    MAP_ENTRY(GridPortableMarshaller.MAP_ENTRY),
+
+    /** */
+    PORTABLE_OBJ(GridPortableMarshaller.OBJ),
+
+    /** */
+    ENUM(GridPortableMarshaller.ENUM),
+
+    /** */
+    ENUM_ARR(GridPortableMarshaller.ENUM_ARR),
+
+    /** */
+    CLASS(GridPortableMarshaller.CLASS),
+
+    /** */
+    PORTABLE(GridPortableMarshaller.PORTABLE_OBJ),
+
+    /** */
+    EXTERNALIZABLE(GridPortableMarshaller.OBJ),
+
+    /** */
+    OBJECT(GridPortableMarshaller.OBJ),
+
+    /** */
+    EXCLUSION(GridPortableMarshaller.OBJ);
+
+    /** Type ID. */
+    private final int typeId;
+
+    /**
+     * @param typeId Type ID.
+     */
+    private BinaryWriteMode(int typeId) {
+        this.typeId = typeId;
+    }
+
+    /**
+     * @return Type ID.
+     */
+    public int typeId() {
+        return typeId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
index 6cb18fb..7bb4c49 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
@@ -19,12 +19,12 @@ package org.apache.ignite.internal.portable;
 
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryIdMapper;
-import org.apache.ignite.internal.portable.streams.PortableHeapOutputStream;
-import org.apache.ignite.internal.portable.streams.PortableOutputStream;
-import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.BinaryRawWriter;
 import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.internal.portable.streams.PortableHeapOutputStream;
+import org.apache.ignite.internal.portable.streams.PortableOutputStream;
+import org.apache.ignite.internal.util.typedef.internal.A;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.IOException;
@@ -35,7 +35,6 @@ import java.math.BigInteger;
 import java.sql.Timestamp;
 import java.util.Collection;
 import java.util.Date;
-import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.UUID;
 
@@ -66,7 +65,6 @@ import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG_AR
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP_ENTRY;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.NULL;
-import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ_ARR;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.OPTM_MARSH;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.PORTABLE_OBJ;
@@ -93,44 +91,26 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** Initial capacity. */
     private static final int INIT_CAP = 1024;
 
-    /** Maximum offset which fits in 1 byte. */
-    private static final int MAX_OFFSET_1 = 1 << 8;
-
-    /** Maximum offset which fits in 2 bytes. */
-    private static final int MAX_OFFSET_2 = 1 << 16;
-
-    /** Thread-local schema. */
-    private static final ThreadLocal<SchemaHolder> SCHEMA = new ThreadLocal<>();
-
     /** */
     private final PortableContext ctx;
 
-    /** */
-    private final int start;
+    /** Output stream. */
+    private final PortableOutputStream out;
 
-    /** */
-    private Class<?> cls;
+    /** Schema. */
+    private final BinaryWriterSchemaHolder schema;
 
     /** */
     private int typeId;
 
-    /** Raw offset position. */
-    private int rawOffPos;
-
     /** */
-    private boolean metaEnabled;
+    private final int start;
 
-    /** */
-    private int metaHashSum;
+    /** Raw offset position. */
+    private int rawOffPos;
 
     /** Handles. */
-    private Map<Object, Integer> handles;
-
-    /** Output stream. */
-    private PortableOutputStream out;
-
-    /** Schema. */
-    private SchemaHolder schema;
+    private BinaryWriterHandles handles;
 
     /** Schema ID. */
     private int schemaId = PortableUtils.schemaInitialId();
@@ -144,40 +124,38 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /**
      * @param ctx Context.
      */
-    BinaryWriterExImpl(PortableContext ctx) {
-        this(ctx, new PortableHeapOutputStream(INIT_CAP));
+    public BinaryWriterExImpl(PortableContext ctx) {
+        this(ctx, BinaryThreadLocalContext.get());
     }
 
     /**
      * @param ctx Context.
-     * @param out Output stream.
+     * @param tlsCtx TLS context.
      */
-    BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out) {
-        this(ctx, out, new IdentityHashMap<Object, Integer>());
+    public BinaryWriterExImpl(PortableContext ctx, BinaryThreadLocalContext tlsCtx) {
+        this(ctx, new PortableHeapOutputStream(INIT_CAP, tlsCtx.chunk()), tlsCtx.schemaHolder(), null);
     }
 
-     /**
-      * @param ctx Context.
-      * @param out Output stream.
-      * @param handles Handles.
-      */
-     private BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out, Map<Object, Integer> handles) {
-         this.ctx = ctx;
-         this.out = out;
-         this.handles = handles;
+    /**
+     * @param ctx Context.
+     * @param out Output stream.
+     * @param handles Handles.
+     */
+    public BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out, BinaryWriterSchemaHolder schema,
+        BinaryWriterHandles handles) {
+        this.ctx = ctx;
+        this.out = out;
+        this.schema = schema;
+        this.handles = handles;
 
-         start = out.position();
-     }
+        start = out.position();
+    }
 
     /**
-     * @param ctx Context.
      * @param typeId Type ID.
      */
-    public BinaryWriterExImpl(PortableContext ctx, int typeId, boolean metaEnabled) {
-        this(ctx);
-
+    public void typeId(int typeId) {
         this.typeId = typeId;
-        this.metaEnabled = metaEnabled;
     }
 
     /**
@@ -188,13 +166,6 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     }
 
     /**
-     * @return Meta data hash sum or {@code null} if meta data is disabled.
-     */
-    @Nullable Integer metaDataHashSum() {
-        return metaEnabled ? metaHashSum : null;
-    }
-
-    /**
      * @param obj Object.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
@@ -210,7 +181,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     void marshal(Object obj, boolean enableReplace) throws BinaryObjectException {
         assert obj != null;
 
-        cls = obj.getClass();
+        Class<?> cls = obj.getClass();
 
         PortableClassDescriptor desc = ctx.descriptorForClass(cls);
 
@@ -218,12 +189,13 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
             throw new BinaryObjectException("Object is not portable: [class=" + cls + ']');
 
         if (desc.excluded()) {
-            doWriteByte(NULL);
+            out.writeByte(NULL);
+
             return;
         }
 
         if (desc.useOptimizedMarshaller()) {
-            writeByte(OPTM_MARSH);
+            out.writeByte(OPTM_MARSH);
 
             try {
                 byte[] arr = ctx.optimizedMarsh().marshal(obj);
@@ -256,7 +228,8 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
             }
 
             if (replacedObj == null) {
-                doWriteByte(NULL);
+                out.writeByte(NULL);
+
                 return;
             }
 
@@ -265,31 +238,10 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
             return;
         }
 
-        typeId = desc.typeId();
-        metaEnabled = desc.userType();
-
         desc.write(obj, this);
     }
 
     /**
-     * @param obj Object.
-     * @return Handle.
-     */
-    int handle(Object obj) {
-        assert obj != null;
-
-        Integer h = handles.get(obj);
-
-        if (h != null)
-            return out.position() - h;
-        else {
-            handles.put(obj, out.position());
-
-            return -1;
-        }
-    }
-
-    /**
      * @return Array.
      */
     public byte[] array() {
@@ -340,18 +292,18 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
         if (useCompactFooter)
             flags |= PortableUtils.FLAG_COMPACT_FOOTER;
-        
-        if (schema != null) {
+
+        if (fieldCnt != 0) {
             flags |= PortableUtils.FLAG_HAS_SCHEMA;
 
             // Write schema ID.
-            out.writeInt(start + SCHEMA_ID_POS, schemaId);
+            out.unsafeWriteInt(start + SCHEMA_ID_POS, schemaId);
 
             // Write schema offset.
-            out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start);
+            out.unsafeWriteInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start);
 
             // Write the schema.
-            int offsetByteCnt = schema.write(this, fieldCnt, useCompactFooter);
+            int offsetByteCnt = schema.write(out, fieldCnt, useCompactFooter);
 
             if (offsetByteCnt == PortableUtils.OFFSET_1)
                 flags |= PortableUtils.FLAG_OFFSET_ONE_BYTE;
@@ -370,28 +322,25 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
                 // If there are no schema, we are free to write raw offset to schema offset.
                 flags |= PortableUtils.FLAG_HAS_RAW;
 
-                out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, rawOffPos - start);
+                out.unsafeWriteInt(start + SCHEMA_OR_RAW_OFF_POS, rawOffPos - start);
             }
             else
-                out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, 0);
+                out.unsafeWriteInt(start + SCHEMA_OR_RAW_OFF_POS, 0);
         }
 
         // Write flags.
-        out.writeShort(start + FLAGS_POS, flags);
+        out.unsafeWriteShort(start + FLAGS_POS, flags);
 
         // Write length.
-        out.writeInt(start + TOTAL_LEN_POS, out.position() - start);
+        out.unsafeWriteInt(start + TOTAL_LEN_POS, out.position() - start);
     }
 
     /**
      * Pop schema.
      */
     public void popSchema() {
-        if (schema != null) {
-            assert fieldCnt > 0;
-
+        if (fieldCnt > 0)
             schema.pop(fieldCnt);
-        }
     }
 
     /**
@@ -415,83 +364,29 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     }
 
     /**
-     * @param val Value.
-     */
-    public void doWriteByte(byte val) {
-        out.writeByte(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteShort(short val) {
-        out.writeShort(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteInt(int val) {
-        out.writeInt(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteLong(long val) {
-        out.writeLong(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteFloat(float val) {
-        out.writeFloat(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteDouble(double val) {
-        out.writeDouble(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteChar(char val) {
-        out.writeChar(val);
-    }
-
-    /**
-     * @param val Value.
-     */
-    public void doWriteBoolean(boolean val) {
-        out.writeBoolean(val);
-    }
-
-    /**
      * @param val String value.
      */
     public void doWriteDecimal(@Nullable BigDecimal val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(DECIMAL);
+            out.unsafeEnsure(1 + 4 + 4);
+
+            out.unsafeWriteByte(DECIMAL);
 
             BigInteger intVal = val.unscaledValue();
 
             if (intVal.signum() == -1) {
                 intVal = intVal.negate();
 
-                out.writeInt(val.scale() | 0x80000000);
+                out.unsafeWriteInt(val.scale() | 0x80000000);
             }
             else
-                out.writeInt(val.scale());
+                out.unsafeWriteInt(val.scale());
 
             byte[] vals = intVal.toByteArray();
 
-            out.writeInt(vals.length);
+            out.unsafeWriteInt(vals.length);
             out.writeByteArray(vals);
         }
     }
@@ -501,13 +396,13 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWriteString(@Nullable String val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(STRING);
-
             byte[] strArr = val.getBytes(UTF_8);
 
-            doWriteInt(strArr.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(STRING);
+            out.unsafeWriteInt(strArr.length);
 
             out.writeByteArray(strArr);
         }
@@ -518,11 +413,12 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWriteUuid(@Nullable UUID uuid) {
         if (uuid == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(UUID);
-            doWriteLong(uuid.getMostSignificantBits());
-            doWriteLong(uuid.getLeastSignificantBits());
+            out.unsafeEnsure(1 + 8 + 8);
+            out.unsafeWriteByte(UUID);
+            out.unsafeWriteLong(uuid.getMostSignificantBits());
+            out.unsafeWriteLong(uuid.getLeastSignificantBits());
         }
     }
 
@@ -531,10 +427,11 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWriteDate(@Nullable Date date) {
         if (date == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(DATE);
-            doWriteLong(date.getTime());
+            out.unsafeEnsure(1 + 8);
+            out.unsafeWriteByte(DATE);
+            out.unsafeWriteLong(date.getTime());
         }
     }
 
@@ -543,11 +440,12 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWriteTimestamp(@Nullable Timestamp ts) {
         if (ts== null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(TIMESTAMP);
-            doWriteLong(ts.getTime());
-            doWriteInt(ts.getNanos() % 1000000);
+            out.unsafeEnsure(1 + 8 + 4);
+            out.unsafeWriteByte(TIMESTAMP);
+            out.unsafeWriteLong(ts.getTime());
+            out.unsafeWriteInt(ts.getNanos() % 1000000);
         }
     }
 
@@ -559,9 +457,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWriteObject(@Nullable Object obj) throws BinaryObjectException {
         if (obj == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, handles);
+            BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, schema, handles());
 
             writer.marshal(obj);
         }
@@ -572,13 +470,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteByteArray(@Nullable byte[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(BYTE_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(BYTE_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeByteArray(val);
         }
@@ -589,13 +488,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteShortArray(@Nullable short[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(SHORT_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(SHORT_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeShortArray(val);
         }
@@ -606,13 +506,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteIntArray(@Nullable int[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(INT_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(INT_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeIntArray(val);
         }
@@ -623,13 +524,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteLongArray(@Nullable long[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(LONG_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(LONG_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeLongArray(val);
         }
@@ -640,13 +542,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteFloatArray(@Nullable float[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(FLOAT_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(FLOAT_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeFloatArray(val);
         }
@@ -657,13 +560,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteDoubleArray(@Nullable double[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(DOUBLE_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(DOUBLE_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeDoubleArray(val);
         }
@@ -674,13 +578,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteCharArray(@Nullable char[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(CHAR_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(CHAR_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeCharArray(val);
         }
@@ -691,13 +596,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteBooleanArray(@Nullable boolean[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(BOOLEAN_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(BOOLEAN_ARR);
+            out.unsafeWriteInt(val.length);
 
             out.writeBooleanArray(val);
         }
@@ -708,13 +614,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteDecimalArray(@Nullable BigDecimal[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(DECIMAL_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(DECIMAL_ARR);
+            out.unsafeWriteInt(val.length);
 
             for (BigDecimal str : val)
                 doWriteDecimal(str);
@@ -726,13 +633,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteStringArray(@Nullable String[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(STRING_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(STRING_ARR);
+            out.unsafeWriteInt(val.length);
 
             for (String str : val)
                 doWriteString(str);
@@ -744,13 +652,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteUuidArray(@Nullable UUID[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(UUID_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(UUID_ARR);
+            out.unsafeWriteInt(val.length);
 
             for (UUID uuid : val)
                 doWriteUuid(uuid);
@@ -762,13 +671,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteDateArray(@Nullable Date[] val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
-            doWriteByte(DATE_ARR);
-            doWriteInt(val.length);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(DATE_ARR);
+            out.unsafeWriteInt(val.length);
 
             for (Date date : val)
                 doWriteDate(date);
@@ -780,13 +690,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
       */
      void doWriteTimestampArray(@Nullable Timestamp[] val) {
          if (val == null)
-             doWriteByte(NULL);
+             out.writeByte(NULL);
          else {
              if (tryWriteAsHandle(val))
                  return;
 
-             doWriteByte(TIMESTAMP_ARR);
-             doWriteInt(val.length);
+             out.unsafeEnsure(1 + 4);
+             out.unsafeWriteByte(TIMESTAMP_ARR);
+             out.unsafeWriteInt(val.length);
 
              for (Timestamp ts : val)
                  doWriteTimestamp(ts);
@@ -799,23 +710,25 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteObjectArray(@Nullable Object[] val) throws BinaryObjectException {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(val))
                 return;
 
             PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
 
-            doWriteByte(OBJ_ARR);
+            out.unsafeEnsure(1 + 4);
+            out.unsafeWriteByte(OBJ_ARR);
 
             if (desc.registered())
-                doWriteInt(desc.typeId());
+                out.unsafeWriteInt(desc.typeId());
             else {
-                doWriteInt(UNREGISTERED_TYPE_ID);
+                out.unsafeWriteInt(UNREGISTERED_TYPE_ID);
+
                 doWriteString(val.getClass().getComponentType().getName());
             }
 
-            doWriteInt(val.length);
+            out.writeInt(val.length);
 
             for (Object obj : val)
                 doWriteObject(obj);
@@ -828,14 +741,15 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteCollection(@Nullable Collection<?> col) throws BinaryObjectException {
         if (col == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(col))
                 return;
 
-            doWriteByte(COL);
-            doWriteInt(col.size());
-            doWriteByte(ctx.collectionType(col.getClass()));
+            out.unsafeEnsure(1 + 4 + 1);
+            out.unsafeWriteByte(COL);
+            out.unsafeWriteInt(col.size());
+            out.unsafeWriteByte(ctx.collectionType(col.getClass()));
 
             for (Object obj : col)
                 doWriteObject(obj);
@@ -848,14 +762,15 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteMap(@Nullable Map<?, ?> map) throws BinaryObjectException {
         if (map == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(map))
                 return;
 
-            doWriteByte(MAP);
-            doWriteInt(map.size());
-            doWriteByte(ctx.mapType(map.getClass()));
+            out.unsafeEnsure(1 + 4 + 1);
+            out.unsafeWriteByte(MAP);
+            out.unsafeWriteInt(map.size());
+            out.unsafeWriteByte(ctx.mapType(map.getClass()));
 
             for (Map.Entry<?, ?> e : map.entrySet()) {
                 doWriteObject(e.getKey());
@@ -870,12 +785,12 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteMapEntry(@Nullable Map.Entry<?, ?> e) throws BinaryObjectException {
         if (e == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             if (tryWriteAsHandle(e))
                 return;
 
-            doWriteByte(MAP_ENTRY);
+            out.writeByte(MAP_ENTRY);
             doWriteObject(e.getKey());
             doWriteObject(e.getValue());
         }
@@ -886,20 +801,22 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteEnum(@Nullable Enum<?> val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass());
 
-            doWriteByte(ENUM);
+            out.unsafeEnsure(1 + 4);
+
+            out.unsafeWriteByte(ENUM);
 
             if (desc.registered())
-                doWriteInt(desc.typeId());
+                out.unsafeWriteInt(desc.typeId());
             else {
-                doWriteInt(UNREGISTERED_TYPE_ID);
+                out.unsafeWriteInt(UNREGISTERED_TYPE_ID);
                 doWriteString(val.getClass().getName());
             }
 
-            doWriteInt(val.ordinal());
+            out.writeInt(val.ordinal());
         }
     }
 
@@ -910,19 +827,23 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
         assert val == null || val.getClass().getComponentType().isEnum();
 
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
-            doWriteByte(ENUM_ARR);
+
+            out.unsafeEnsure(1 + 4);
+
+            out.unsafeWriteByte(ENUM_ARR);
 
             if (desc.registered())
-                doWriteInt(desc.typeId());
+                out.unsafeWriteInt(desc.typeId());
             else {
-                doWriteInt(UNREGISTERED_TYPE_ID);
+                out.unsafeWriteInt(UNREGISTERED_TYPE_ID);
+
                 doWriteString(val.getClass().getComponentType().getName());
             }
 
-            doWriteInt(val.length);
+            out.writeInt(val.length);
 
             // TODO: Denis: Redundant data for each element of the array.
             for (Object o : val)
@@ -935,16 +856,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void doWriteClass(@Nullable Class val) {
         if (val == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
             PortableClassDescriptor desc = ctx.descriptorForClass(val);
 
-            doWriteByte(CLASS);
+            out.unsafeEnsure(1 + 4);
+
+            out.unsafeWriteByte(CLASS);
 
             if (desc.registered())
-                doWriteInt(desc.typeId());
+                out.unsafeWriteInt(desc.typeId());
             else {
-                doWriteInt(UNREGISTERED_TYPE_ID);
+                out.unsafeWriteInt(UNREGISTERED_TYPE_ID);
+
                 doWriteString(val.getClass().getName());
             }
         }
@@ -955,30 +879,37 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     public void doWritePortableObject(@Nullable BinaryObjectImpl po) {
         if (po == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            doWriteByte(PORTABLE_OBJ);
-
             byte[] poArr = po.array();
 
-            doWriteInt(poArr.length);
+            out.unsafeEnsure(1 + 4 + poArr.length + 4);
 
+            out.unsafeWriteByte(PORTABLE_OBJ);
+            out.unsafeWriteInt(poArr.length);
             out.writeByteArray(poArr);
-
-            doWriteInt(po.start());
+            out.unsafeWriteInt(po.start());
         }
     }
 
     /**
      * @param val Value.
      */
+    void writeByteFieldPrimitive(byte val) {
+        out.unsafeEnsure(1 + 1);
+
+        out.unsafeWriteByte(BYTE);
+        out.unsafeWriteByte(val);
+    }
+
+    /**
+     * @param val Value.
+     */
     void writeByteField(@Nullable Byte val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(BYTE);
-            doWriteByte(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeByteFieldPrimitive(val);
     }
 
     /**
@@ -991,13 +922,31 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /**
      * @param val Value.
      */
+    void writeShortFieldPrimitive(short val) {
+        out.unsafeEnsure(1 + 2);
+
+        out.unsafeWriteByte(SHORT);
+        out.unsafeWriteShort(val);
+    }
+
+    /**
+     * @param val Value.
+     */
     void writeShortField(@Nullable Short val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(SHORT);
-            doWriteShort(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeShortFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeIntFieldPrimitive(int val) {
+        out.unsafeEnsure(1 + 4);
+
+        out.unsafeWriteByte(INT);
+        out.unsafeWriteInt(val);
     }
 
     /**
@@ -1005,11 +954,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeIntField(@Nullable Integer val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(INT);
-            doWriteInt(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeIntFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeLongFieldPrimitive(long val) {
+        out.unsafeEnsure(1 + 8);
+
+        out.unsafeWriteByte(LONG);
+        out.unsafeWriteLong(val);
     }
 
     /**
@@ -1017,11 +974,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeLongField(@Nullable Long val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(LONG);
-            doWriteLong(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeLongFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeFloatFieldPrimitive(float val) {
+        out.unsafeEnsure(1 + 4);
+
+        out.unsafeWriteByte(FLOAT);
+        out.unsafeWriteFloat(val);
     }
 
     /**
@@ -1029,11 +994,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeFloatField(@Nullable Float val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(FLOAT);
-            doWriteFloat(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeFloatFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeDoubleFieldPrimitive(double val) {
+        out.unsafeEnsure(1 + 8);
+
+        out.unsafeWriteByte(DOUBLE);
+        out.unsafeWriteDouble(val);
     }
 
     /**
@@ -1041,11 +1014,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeDoubleField(@Nullable Double val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(DOUBLE);
-            doWriteDouble(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeDoubleFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeCharFieldPrimitive(char val) {
+        out.unsafeEnsure(1 + 2);
+
+        out.unsafeWriteByte(CHAR);
+        out.unsafeWriteChar(val);
     }
 
     /**
@@ -1053,11 +1034,19 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeCharField(@Nullable Character val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(CHAR);
-            doWriteChar(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeCharFieldPrimitive(val);
+    }
+
+    /**
+     * @param val Value.
+     */
+    void writeBooleanFieldPrimitive(boolean val) {
+        out.unsafeEnsure(1 + 1);
+
+        out.unsafeWriteByte(BOOLEAN);
+        out.unsafeWriteBoolean(val);
     }
 
     /**
@@ -1065,11 +1054,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      */
     void writeBooleanField(@Nullable Boolean val) {
         if (val == null)
-            doWriteByte(NULL);
-        else {
-            doWriteByte(BOOLEAN);
-            doWriteBoolean(val);
-        }
+            out.writeByte(NULL);
+        else
+            writeBooleanFieldPrimitive(val);
     }
 
     /**
@@ -1262,95 +1249,95 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException {
-        writeFieldId(fieldName, BYTE);
+        writeFieldId(fieldName);
         writeByteField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeByte(byte val) throws BinaryObjectException {
-        doWriteByte(val);
+        out.writeByte(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeShort(String fieldName, short val) throws BinaryObjectException {
-        writeFieldId(fieldName, SHORT);
+        writeFieldId(fieldName);
         writeShortField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeShort(short val) throws BinaryObjectException {
-        doWriteShort(val);
+        out.writeShort(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeInt(String fieldName, int val) throws BinaryObjectException {
-        writeFieldId(fieldName, INT);
+        writeFieldId(fieldName);
         writeIntField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeInt(int val) throws BinaryObjectException {
-        doWriteInt(val);
+        out.writeInt(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeLong(String fieldName, long val) throws BinaryObjectException {
-        writeFieldId(fieldName, LONG);
+        writeFieldId(fieldName);
         writeLongField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeLong(long val) throws BinaryObjectException {
-        doWriteLong(val);
+        out.writeLong(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException {
-        writeFieldId(fieldName, FLOAT);
+        writeFieldId(fieldName);
         writeFloatField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeFloat(float val) throws BinaryObjectException {
-        doWriteFloat(val);
+        out.writeFloat(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException {
-        writeFieldId(fieldName, DOUBLE);
+        writeFieldId(fieldName);
         writeDoubleField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDouble(double val) throws BinaryObjectException {
-        doWriteDouble(val);
+        out.writeDouble(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeChar(String fieldName, char val) throws BinaryObjectException {
-        writeFieldId(fieldName, CHAR);
+        writeFieldId(fieldName);
         writeCharField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeChar(char val) throws BinaryObjectException {
-        doWriteChar(val);
+        out.writeChar(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException {
-        writeFieldId(fieldName, BOOLEAN);
+        writeFieldId(fieldName);
         writeBooleanField(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeBoolean(boolean val) throws BinaryObjectException {
-        doWriteBoolean(val);
+        out.writeBoolean(val);
     }
 
     /** {@inheritDoc} */
     @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException {
-        writeFieldId(fieldName, DECIMAL);
+        writeFieldId(fieldName);
         writeDecimalField(val);
     }
 
@@ -1361,7 +1348,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException {
-        writeFieldId(fieldName, STRING);
+        writeFieldId(fieldName);
         writeStringField(val);
     }
 
@@ -1372,7 +1359,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException {
-        writeFieldId(fieldName, UUID);
+        writeFieldId(fieldName);
         writeUuidField(val);
     }
 
@@ -1383,7 +1370,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException {
-        writeFieldId(fieldName, DATE);
+        writeFieldId(fieldName);
         writeDateField(val);
     }
 
@@ -1394,7 +1381,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException {
-        writeFieldId(fieldName, TIMESTAMP);
+        writeFieldId(fieldName);
         writeTimestampField(val);
     }
 
@@ -1405,7 +1392,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException {
-        writeFieldId(fieldName, OBJ);
+        writeFieldId(fieldName);
         writeObjectField(obj);
     }
 
@@ -1417,9 +1404,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public void writeObjectDetached(@Nullable Object obj) throws BinaryObjectException {
         if (obj == null)
-            doWriteByte(NULL);
+            out.writeByte(NULL);
         else {
-            BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, new IdentityHashMap<Object, Integer>());
+            BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, schema, null);
 
             writer.marshal(obj);
         }
@@ -1427,7 +1414,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, BYTE_ARR);
+        writeFieldId(fieldName);
         writeByteArrayField(val);
     }
 
@@ -1438,7 +1425,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, SHORT_ARR);
+        writeFieldId(fieldName);
         writeShortArrayField(val);
     }
 
@@ -1449,7 +1436,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, INT_ARR);
+        writeFieldId(fieldName);
         writeIntArrayField(val);
     }
 
@@ -1460,7 +1447,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, LONG_ARR);
+        writeFieldId(fieldName);
         writeLongArrayField(val);
     }
 
@@ -1471,7 +1458,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, FLOAT_ARR);
+        writeFieldId(fieldName);
         writeFloatArrayField(val);
     }
 
@@ -1483,7 +1470,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public void writeDoubleArray(String fieldName, @Nullable double[] val)
         throws BinaryObjectException {
-        writeFieldId(fieldName, DOUBLE_ARR);
+        writeFieldId(fieldName);
         writeDoubleArrayField(val);
     }
 
@@ -1494,7 +1481,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, CHAR_ARR);
+        writeFieldId(fieldName);
         writeCharArrayField(val);
     }
 
@@ -1506,7 +1493,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val)
         throws BinaryObjectException {
-        writeFieldId(fieldName, BOOLEAN_ARR);
+        writeFieldId(fieldName);
         writeBooleanArrayField(val);
     }
 
@@ -1518,7 +1505,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val)
         throws BinaryObjectException {
-        writeFieldId(fieldName, DECIMAL_ARR);
+        writeFieldId(fieldName);
         writeDecimalArrayField(val);
     }
 
@@ -1530,7 +1517,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public void writeStringArray(String fieldName, @Nullable String[] val)
         throws BinaryObjectException {
-        writeFieldId(fieldName, STRING_ARR);
+        writeFieldId(fieldName);
         writeStringArrayField(val);
     }
 
@@ -1541,7 +1528,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, UUID_ARR);
+        writeFieldId(fieldName);
         writeUuidArrayField(val);
     }
 
@@ -1552,7 +1539,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, DATE_ARR);
+        writeFieldId(fieldName);
         writeDateArrayField(val);
     }
 
@@ -1563,7 +1550,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, TIMESTAMP_ARR);
+        writeFieldId(fieldName);
         writeTimestampArrayField(val);
     }
 
@@ -1574,7 +1561,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
      /** {@inheritDoc} */
     @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, OBJ_ARR);
+        writeFieldId(fieldName);
         writeObjectArrayField(val);
     }
 
@@ -1586,7 +1573,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col)
         throws BinaryObjectException {
-        writeFieldId(fieldName, COL);
+        writeFieldId(fieldName);
         writeCollectionField(col);
     }
 
@@ -1598,7 +1585,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     /** {@inheritDoc} */
     @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map)
         throws BinaryObjectException {
-        writeFieldId(fieldName, MAP);
+        writeFieldId(fieldName);
         writeMapField(map);
     }
 
@@ -1609,7 +1596,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException {
-        writeFieldId(fieldName, ENUM);
+        writeFieldId(fieldName);
         writeEnumField(val);
     }
 
@@ -1620,7 +1607,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException {
-        writeFieldId(fieldName, ENUM_ARR);
+        writeFieldId(fieldName);
         writeEnumArrayField(val);
     }
 
@@ -1672,22 +1659,22 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
 
     /** {@inheritDoc} */
     @Override public void writeByte(int v) throws IOException {
-        doWriteByte((byte) v);
+        out.writeByte((byte) v);
     }
 
     /** {@inheritDoc} */
     @Override public void writeShort(int v) throws IOException {
-        doWriteShort((short) v);
+        out.writeShort((short) v);
     }
 
     /** {@inheritDoc} */
     @Override public void writeChar(int v) throws IOException {
-        doWriteChar((char) v);
+        out.writeChar((char) v);
     }
 
     /** {@inheritDoc} */
     @Override public void write(int b) throws IOException {
-        doWriteByte((byte) b);
+        out.writeByte((byte) b);
     }
 
     /** {@inheritDoc} */
@@ -1709,12 +1696,11 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      * @param fieldName Field name.
      * @throws org.apache.ignite.binary.BinaryObjectException If fields are not allowed.
      */
-    private void writeFieldId(String fieldName, byte fieldType) throws BinaryObjectException {
+    private void writeFieldId(String fieldName) throws BinaryObjectException {
         A.notNull(fieldName, "fieldName");
 
         if (rawOffPos != 0)
-            throw new BinaryObjectException("Individual field can't be written after raw writer is acquired " +
-                "via rawWriter() method. Consider fixing serialization logic for class: " + cls.getName());
+            throw new BinaryObjectException("Individual field can't be written after raw writer is acquired.");
 
         if (idMapper == null)
             idMapper = ctx.userTypeIdMapper(typeId);
@@ -1722,9 +1708,6 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
         int id = idMapper.fieldId(typeId, fieldName);
 
         writeFieldId(id);
-
-        if (metaEnabled)
-            metaHashSum = 31 * metaHashSum + (id + fieldType);
     }
 
     /**
@@ -1734,17 +1717,22 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     public void writeFieldId(int fieldId) {
         int fieldOff = out.position() - start;
 
-        if (schema == null) {
-            schema = SCHEMA.get();
+        // Advance schema hash.
+        schemaId = PortableUtils.updateSchemaId(schemaId, fieldId);
 
-            if (schema == null) {
-                schema = new SchemaHolder();
+        schema.push(fieldId, fieldOff);
 
-                SCHEMA.set(schema);
-            }
-        }
+        fieldCnt++;
+    }
 
-        schemaId = PortableUtils.updateSchemaId(schemaId, fieldId);
+    /**
+     * Write field ID without schema ID update. This method should be used when schema ID is stable because class
+     * is seializable.
+     *
+     * @param fieldId Field ID.
+     */
+    public void writeFieldIdNoSchemaUpdate(int fieldId) {
+        int fieldOff = out.position() - start;
 
         schema.push(fieldId, fieldOff);
 
@@ -1752,7 +1740,14 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     }
 
     /**
-     * @return Current schema ID.
+     * @param schemaId Schema ID.
+     */
+    public void schemaId(int schemaId) {
+        this.schemaId = schemaId;
+    }
+
+    /**
+     * @return Schema ID.
      */
     public int schemaId() {
         return schemaId;
@@ -1771,22 +1766,43 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     }
 
     /**
+     * Get current handles. If they are {@code null}, then we should create them. Otherwise we will not see updates
+     * performed by child writers.
+     *
+     * @return Handles.
+     */
+    private BinaryWriterHandles handles() {
+        if (handles == null)
+            handles = new BinaryWriterHandles();
+
+        return handles;
+    }
+
+    /**
      * Attempts to write the object as a handle.
      *
      * @param obj Object to write.
      * @return {@code true} if the object has been written as a handle.
      */
     boolean tryWriteAsHandle(Object obj) {
-        int handle = handle(obj);
+        assert obj != null;
 
-        if (handle >= 0) {
-            doWriteByte(GridPortableMarshaller.HANDLE);
-            doWriteInt(handle);
+        int pos = out.position();
+
+        BinaryWriterHandles handles0 = handles();
+
+        int old = handles0.put(obj, pos);
+
+        if (old == BinaryWriterHandles.POS_NULL)
+            return false;
+        else {
+            out.unsafeEnsure(1 + 4);
+
+            out.unsafeWriteByte(GridPortableMarshaller.HANDLE);
+            out.unsafeWriteInt(pos - old);
 
             return true;
         }
-
-        return false;
     }
 
     /**
@@ -1796,9 +1812,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
      * @return New writer.
      */
     public BinaryWriterExImpl newWriter(int typeId) {
-        BinaryWriterExImpl res = new BinaryWriterExImpl(ctx, out, handles);
+        BinaryWriterExImpl res = new BinaryWriterExImpl(ctx, out, schema, handles());
 
-        res.typeId = typeId;
+        res.typeId(typeId);
 
         return res;
     }
@@ -1809,138 +1825,4 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
     public PortableContext context() {
         return ctx;
     }
-
-    /**
-     * Schema holder.
-     */
-    private static class SchemaHolder {
-        /** Grow step. */
-        private static final int GROW_STEP = 64;
-
-        /** Maximum stable size. */
-        private static final int MAX_SIZE = 1024;
-
-        /** Data. */
-        private int[] data;
-
-        /** Index. */
-        private int idx;
-
-        /**
-         * Constructor.
-         */
-        public SchemaHolder() {
-            data = new int[GROW_STEP];
-        }
-
-        /**
-         * Push another frame.
-         *
-         * @param id Field ID.
-         * @param off Field offset.
-         */
-        public void push(int id, int off) {
-            if (idx == data.length) {
-                int[] data0 = new int[data.length + GROW_STEP];
-
-                System.arraycopy(data, 0, data0, 0, data.length);
-
-                data = data0;
-            }
-
-            data[idx] = id;
-            data[idx + 1] = off;
-
-            idx += 2;
-        }
-
-        /**
-         * Build the schema.
-         *
-         * @param builder Builder.
-         * @param fieldCnt Fields count.
-         */
-        public void build(PortableSchema.Builder builder, int fieldCnt) {
-            for (int curIdx = idx - fieldCnt * 2; curIdx < idx; curIdx += 2)
-                builder.addField(data[curIdx]);
-        }
-
-        /**
-         * Write collected frames and pop them.
-         *
-         * @param writer Writer.
-         * @param fieldCnt Count.
-         * @param compactFooter Whether footer should be written in compact form.
-         * @return Amount of bytes dedicated to each field offset. Could be 1, 2 or 4.
-         */
-        public int write(BinaryWriterExImpl writer, int fieldCnt, boolean compactFooter) {
-            int startIdx = idx - fieldCnt * 2;
-
-            assert startIdx >= 0;
-
-            int lastOffset = data[idx - 1];
-
-            int res;
-
-            if (compactFooter) {
-                if (lastOffset < MAX_OFFSET_1) {
-                    for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
-                        writer.writeByte((byte)data[curIdx]);
-
-                    res = PortableUtils.OFFSET_1;
-                }
-                else if (lastOffset < MAX_OFFSET_2) {
-                    for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
-                        writer.writeShort((short)data[curIdx]);
-
-                    res = PortableUtils.OFFSET_2;
-                }
-                else {
-                    for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
-                        writer.writeInt(data[curIdx]);
-
-                    res = PortableUtils.OFFSET_4;
-                }
-            }
-            else {
-                if (lastOffset < MAX_OFFSET_1) {
-                    for (int curIdx = startIdx; curIdx < idx;) {
-                        writer.writeInt(data[curIdx++]);
-                        writer.writeByte((byte) data[curIdx++]);
-                    }
-
-                    res = PortableUtils.OFFSET_1;
-                }
-                else if (lastOffset < MAX_OFFSET_2) {
-                    for (int curIdx = startIdx; curIdx < idx;) {
-                        writer.writeInt(data[curIdx++]);
-                        writer.writeShort((short)data[curIdx++]);
-                    }
-
-                    res = PortableUtils.OFFSET_2;
-                }
-                else {
-                    for (int curIdx = startIdx; curIdx < idx;) {
-                        writer.writeInt(data[curIdx++]);
-                        writer.writeInt(data[curIdx++]);
-                    }
-
-                    res = PortableUtils.OFFSET_4;
-                }
-            }
-
-            return res;
-        }
-
-        /**
-         * Pop current object's frame.
-         */
-        public void pop(int fieldCnt) {
-            idx = idx - fieldCnt * 2;
-
-            // Shrink data array if needed.
-            if (idx == 0 && data.length > MAX_SIZE)
-                data = new int[MAX_SIZE];
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterHandles.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterHandles.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterHandles.java
new file mode 100644
index 0000000..2a47a2b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterHandles.java
@@ -0,0 +1,101 @@
+/*
+ * 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.portable;
+
+import java.util.IdentityHashMap;
+
+/**
+ * Writer handles. Aimed to delay hash map allocation for some time until it is clearly evident that it is needed.
+ */
+public class BinaryWriterHandles {
+    /** Value denoting null position. */
+    public static final int POS_NULL = -1;
+
+    /** Mode: empty. */
+    private static final int MODE_EMPTY = 0;
+
+    /** Mode: single object. */
+    private static final int MODE_SINGLE = 1;
+
+    /** Mode: multiple objects. */
+    private static final int MODE_MULTIPLE = 2;
+
+    /** Data. This is either an object or a map. */
+    private Object data;
+
+    /** Position.  */
+    private int singlePos;
+
+    /** Mode. */
+    private int mode = MODE_EMPTY;
+
+    /**
+     * Put object to registry and return previous position (if any).
+     *
+     * @param obj Object.
+     * @param pos Position.
+     * @return Old position.
+     */
+    @SuppressWarnings("unchecked")
+    public int put(Object obj, int pos) {
+        assert obj != null;
+        assert pos >= 0;
+
+        switch (mode) {
+            case MODE_EMPTY:
+                this.data = obj;
+                this.singlePos = pos;
+                this.mode = MODE_SINGLE;
+
+                return POS_NULL;
+
+            case MODE_SINGLE:
+                if (this.data == obj)
+                    return singlePos;
+                else {
+                    IdentityHashMap<Object, Integer> newData = new IdentityHashMap<>(2);
+
+                    newData.put(data, singlePos);
+                    newData.put(obj, pos);
+
+                    this.data = newData;
+                    this.singlePos = -1;
+                    this.mode = MODE_MULTIPLE;
+
+                    return POS_NULL;
+                }
+
+            default:
+                assert mode == MODE_MULTIPLE;
+
+                IdentityHashMap<Object, Integer> data0 = (IdentityHashMap<Object, Integer>)data;
+
+                Integer oldPos = data0.put(obj, pos);
+
+                if (oldPos != null) {
+                    // Restore initial position and return it.
+                    data0.put(obj, oldPos);
+
+                    return oldPos;
+                }
+                else
+                    return POS_NULL;
+
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterSchemaHolder.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterSchemaHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterSchemaHolder.java
new file mode 100644
index 0000000..c7400d0
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterSchemaHolder.java
@@ -0,0 +1,148 @@
+/*
+ * 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.portable;
+
+import org.apache.ignite.internal.portable.streams.PortableOutputStream;
+
+/**
+ * Binary writer schema holder.
+ */
+public class BinaryWriterSchemaHolder {
+    /** Maximum offset which fits in 1 byte. */
+    private static final int MAX_OFFSET_1 = 1 << 8;
+
+    /** Maximum offset which fits in 2 bytes. */
+    private static final int MAX_OFFSET_2 = 1 << 16;
+
+    /** Grow step. */
+    private static final int GROW_STEP = 64;
+
+    /** Data. */
+    private int[] data = new int[GROW_STEP];
+
+    /** Index. */
+    private int idx;
+
+    /**
+     * Push another frame.
+     *
+     * @param id Field ID.
+     * @param off Field offset.
+     */
+    public void push(int id, int off) {
+        if (idx == data.length) {
+            int[] data0 = new int[data.length + GROW_STEP];
+
+            System.arraycopy(data, 0, data0, 0, data.length);
+
+            data = data0;
+        }
+
+        data[idx] = id;
+        data[idx + 1] = off;
+
+        idx += 2;
+    }
+
+    /**
+     * Build the schema.
+     *
+     * @param builder Builder.
+     * @param fieldCnt Fields count.
+     */
+    public void build(PortableSchema.Builder builder, int fieldCnt) {
+        for (int curIdx = idx - fieldCnt * 2; curIdx < idx; curIdx += 2)
+            builder.addField(data[curIdx]);
+    }
+
+    /**
+     * Write collected frames and pop them.
+     *
+     * @param out Output stream.
+     * @param fieldCnt Count.
+     * @param compactFooter Whether footer should be written in compact form.
+     * @return Amount of bytes dedicated to each field offset. Could be 1, 2 or 4.
+     */
+    public int write(PortableOutputStream out, int fieldCnt, boolean compactFooter) {
+        int startIdx = idx - fieldCnt * 2;
+        assert startIdx >= 0;
+
+        // Ensure there are at least 8 bytes for each field to allow for unsafe writes.
+        out.unsafeEnsure(fieldCnt << 3);
+
+        int lastOffset = data[idx - 1];
+
+        int res;
+
+        if (compactFooter) {
+            if (lastOffset < MAX_OFFSET_1) {
+                for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
+                    out.unsafeWriteByte((byte)data[curIdx]);
+
+                res = PortableUtils.OFFSET_1;
+            }
+            else if (lastOffset < MAX_OFFSET_2) {
+                for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
+                    out.unsafeWriteShort((short) data[curIdx]);
+
+                res = PortableUtils.OFFSET_2;
+            }
+            else {
+                for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
+                    out.unsafeWriteInt(data[curIdx]);
+
+                res = PortableUtils.OFFSET_4;
+            }
+        }
+        else {
+            if (lastOffset < MAX_OFFSET_1) {
+                for (int curIdx = startIdx; curIdx < idx;) {
+                    out.unsafeWriteInt(data[curIdx++]);
+                    out.unsafeWriteByte((byte) data[curIdx++]);
+                }
+
+                res = PortableUtils.OFFSET_1;
+            }
+            else if (lastOffset < MAX_OFFSET_2) {
+                for (int curIdx = startIdx; curIdx < idx;) {
+                    out.unsafeWriteInt(data[curIdx++]);
+                    out.unsafeWriteShort((short) data[curIdx++]);
+                }
+
+                res = PortableUtils.OFFSET_2;
+            }
+            else {
+                for (int curIdx = startIdx; curIdx < idx;) {
+                    out.unsafeWriteInt(data[curIdx++]);
+                    out.unsafeWriteInt(data[curIdx++]);
+                }
+
+                res = PortableUtils.OFFSET_4;
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * Pop current object's frame.
+     */
+    public void pop(int fieldCnt) {
+        idx = idx - fieldCnt * 2;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
index 056a7c7..9c61ef2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.portable;
 
+import org.apache.ignite.internal.portable.streams.PortableHeapInputStream;
 import org.apache.ignite.internal.portable.streams.PortableInputStream;
 import org.apache.ignite.internal.portable.streams.PortableOutputStream;
 import org.apache.ignite.binary.BinaryObjectException;
@@ -254,7 +255,8 @@ public class GridPortableMarshaller {
     @Nullable public <T> T unmarshal(byte[] bytes, @Nullable ClassLoader clsLdr) throws BinaryObjectException {
         assert bytes != null;
 
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, bytes, 0, clsLdr);
+        BinaryReaderExImpl reader =
+            new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(bytes, 0), clsLdr, new BinaryReaderHandles());
 
         return (T)reader.unmarshal();
     }
@@ -283,7 +285,8 @@ public class GridPortableMarshaller {
         if (arr[0] == NULL)
             return null;
 
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, arr, 0, ldr);
+        BinaryReaderExImpl reader =
+            new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, 0), ldr, new BinaryReaderHandles());
 
         return (T)reader.deserialize();
     }
@@ -295,7 +298,7 @@ public class GridPortableMarshaller {
      * @return Writer.
      */
     public BinaryWriterExImpl writer(PortableOutputStream out) {
-        return new BinaryWriterExImpl(ctx, out);
+        return new BinaryWriterExImpl(ctx, out, BinaryThreadLocalContext.get().schemaHolder(), null);
     }
 
     /**
@@ -306,7 +309,7 @@ public class GridPortableMarshaller {
      */
     public BinaryReaderExImpl reader(PortableInputStream in) {
         // TODO: IGNITE-1272 - Is class loader needed here?
-        return new BinaryReaderExImpl(ctx, in, in.position(), null);
+        return new BinaryReaderExImpl(ctx, in, null, new BinaryReaderHandles());
     }
 
     /**


[4/5] ignite git commit: IGNITE-1917: Binary protocol performance optimizations.

Posted by vo...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/4a1af37e/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
index 6ff3047..6ba5981 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
@@ -24,9 +24,7 @@ import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.BinaryRawReader;
 import org.apache.ignite.binary.BinaryReader;
-import org.apache.ignite.internal.portable.streams.PortableHeapInputStream;
 import org.apache.ignite.internal.portable.streams.PortableInputStream;
-import org.apache.ignite.internal.util.GridEnumCache;
 import org.apache.ignite.internal.util.lang.GridMapEntry;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -117,169 +115,166 @@ import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID_AR
  */
 @SuppressWarnings("unchecked")
 public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, ObjectInput {
-    /** */
+    /** Portable context. */
     private final PortableContext ctx;
 
-    /** */
+    /** Input stream. */
     private final PortableInputStream in;
 
-    /** */
-    private final int start;
-
-    /** */
-    private final PortableReaderContext rCtx;
-
-    /** */
+    /** Class loaded. */
     private final ClassLoader ldr;
 
-    /** */
-    private PortableClassDescriptor desc;
+    /** Reader context which is constantly passed between objects. */
+    private final BinaryReaderHandles rCtx;
 
-    /** Flag indicating that object header was parsed. */
-    private boolean hdrParsed;
+    /** */
+    private final int start;
 
     /** Type ID. */
-    private int typeId;
+    private final int typeId;
 
     /** Raw offset. */
-    private int rawOff;
+    private final int rawOff;
 
     /** */
-    private int hdrLen;
+    private final int hdrLen;
 
     /** Footer start. */
-    private int footerStart;
+    private final int footerStart;
 
     /** Footer end. */
-    private int footerLen;
+    private final int footerLen;
 
     /** ID mapper. */
-    private BinaryIdMapper idMapper;
+    private final BinaryIdMapper idMapper;
 
     /** Schema Id. */
-    private int schemaId;
+    private final int schemaId;
 
     /** Whether this is user type or not. */
-    private boolean userType;
+    private final boolean userType;
 
     /** Whether field IDs exist. */
-    private int fieldIdLen;
+    private final int fieldIdLen;
 
     /** Offset size in bytes. */
-    private int fieldOffsetLen;
+    private final int fieldOffsetLen;
 
     /** Object schema. */
-    private PortableSchema schema;
+    private final PortableSchema schema;
 
-    /**
-     * @param ctx Context.
-     * @param arr Array.
-     * @param start Start.
-     * @param ldr Class loader.
-     */
-    public BinaryReaderExImpl(PortableContext ctx, byte[] arr, int start, ClassLoader ldr) {
-        this(ctx, new PortableHeapInputStream(arr), start, ldr, new PortableReaderContext());
-    }
+    /** Whether passed IDs matches schema order. Reset to false as soon as a single mismatch detected. */
+    private boolean matching = true;
 
-    /**
-     * @param ctx Context.
-     * @param in Input stream.
-     * @param start Start.
-     */
-    BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, int start, ClassLoader ldr) {
-        this(ctx, in, start, ldr, new PortableReaderContext());
-    }
+    /** Order of a field whose match is expected. */
+    private int matchingOrder;
 
     /**
+     * Constructor.
+     *
      * @param ctx Context.
      * @param in Input stream.
-     * @param start Start.
+     * @param ldr Class loader.
      * @param rCtx Context.
      */
-    BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, int start, ClassLoader ldr,
-        PortableReaderContext rCtx) {
+    public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr, BinaryReaderHandles rCtx) {
+        // Initialize base members.
         this.ctx = ctx;
         this.in = in;
-        this.start = start;
         this.ldr = ldr;
         this.rCtx = rCtx;
 
-        in.position(start);
-    }
+        start = in.position();
 
-    /**
-     * Preloads typeId from the input array.
-     */
-    private void parseHeaderIfNeeded() {
-        if (hdrParsed)
-            return;
+        // Parse header if possible.
+        byte hdr = in.readBytePositioned(start);
 
-        int retPos = in.position();
+        if (hdr == GridPortableMarshaller.OBJ) {
+            // Skip header.
+            in.readByte();
 
-        in.position(start);
+            // Ensure protocol is fine.
+            PortableUtils.checkProtocolVersion(in.readByte());
 
-        byte hdr = in.readByte();
+            // Read and parse flags.
+            short flags = in.readShort();
 
-        if (hdr != GridPortableMarshaller.OBJ)
-            throw new BinaryObjectException("Invalid header [pos=" + retPos + "expected=" + GridPortableMarshaller.OBJ +
-                ", actual=" + hdr + ']');
+            userType = PortableUtils.isUserType(flags);
 
-        PortableUtils.checkProtocolVersion(in.readByte());
+            fieldIdLen = PortableUtils.fieldIdLength(flags);
+            fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
 
-        short flags = in.readShort();
+            int typeId0 = in.readIntPositioned(start + GridPortableMarshaller.TYPE_ID_POS);
 
-        userType = PortableUtils.isUserType(flags);
+            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(in, start);
 
-        fieldIdLen = PortableUtils.fieldIdLength(flags);
-        fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
+            footerStart = footer.get1();
+            footerLen = footer.get2() - footerStart;
 
-        typeId = in.readIntPositioned(start + GridPortableMarshaller.TYPE_ID_POS);
+            schemaId = in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_ID_POS);
 
-        IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(in, start);
+            rawOff = PortableUtils.rawOffsetAbsolute(in, start);
 
-        footerStart = footer.get1();
-        footerLen = footer.get2() - footerStart;
+            if (typeId0 == UNREGISTERED_TYPE_ID) {
+                // Skip to the class name position.
+                in.position(start + GridPortableMarshaller.DFLT_HDR_LEN);
 
-        schemaId = in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_ID_POS);
+                int off = in.position();
 
-        rawOff = PortableUtils.rawOffsetAbsolute(in, start);
+                Class cls = doReadClass(typeId0);
 
-        if (typeId == UNREGISTERED_TYPE_ID) {
-            // Skip to the class name position.
-            in.position(start + GridPortableMarshaller.DFLT_HDR_LEN);
+                // registers class by typeId, at least locally if the cache is not ready yet.
+                PortableClassDescriptor desc = ctx.descriptorForClass(cls);
 
-            int off = in.position();
+                typeId = desc.typeId();
 
-            Class cls = doReadClass(typeId);
+                int clsNameLen = in.position() - off;
 
-            // registers class by typeId, at least locally if the cache is not ready yet.
-            PortableClassDescriptor desc = ctx.descriptorForClass(cls);
+                hdrLen = DFLT_HDR_LEN + clsNameLen;
+            }
+            else {
+                typeId = typeId0;
 
-            typeId = desc.typeId();
+                hdrLen = DFLT_HDR_LEN;
+            }
 
-            int clsNameLen = in.position() - off;
+            idMapper = userType ? ctx.userTypeIdMapper(typeId) : null;
+            schema = PortableUtils.hasSchema(flags) ? getOrCreateSchema() : null;
 
-            hdrLen = DFLT_HDR_LEN + clsNameLen;
+            in.position(start);
         }
-        else
-            hdrLen = DFLT_HDR_LEN;
-
-        // Restore state.
-        in.position(retPos);
+        else {
+            typeId = 0;
+            rawOff = 0;
+            hdrLen = 0;
+            footerStart = 0;
+            footerLen = 0;
+            idMapper = null;
+            schemaId = 0;
+            userType = false;
+            fieldIdLen = 0;
+            fieldOffsetLen = 0;
+            schema = null;
+        }
+    }
 
-        hdrParsed = true;
+    /**
+     * @return Handles.
+     */
+    public BinaryReaderHandles handles() {
+        return rCtx;
     }
 
     /**
      * @return Descriptor.
      */
     PortableClassDescriptor descriptor() {
-        return desc;
+        return ctx.descriptorForTypeId(userType, typeId, ldr);
     }
 
     /**
      * @return Unmarshalled value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable Object unmarshal() throws BinaryObjectException {
         return unmarshal(false);
@@ -288,9 +283,12 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     /**
      * @param offset Offset in the array.
      * @return Unmarshalled value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     public Object unmarshal(int offset) throws BinaryObjectException {
+        // Random reads prevent any further speculations.
+        matching = false;
+
         in.position(offset);
 
         return in.position() >= 0 ? unmarshal() : null;
@@ -299,7 +297,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     /**
      * @param fieldName Field name.
      * @return Unmarshalled value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable Object unmarshalField(String fieldName) throws BinaryObjectException {
         return hasField(fieldName) ? unmarshal() : null;
@@ -308,56 +306,41 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     /**
      * @param fieldId Field ID.
      * @return Unmarshalled value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable Object unmarshalField(int fieldId) throws BinaryObjectException {
-        parseHeaderIfNeeded();
-
-        return hasField(fieldId) ? unmarshal() : null;
-    }
-
-    /**
-     * Unmarshal field by absolute position.
-     *
-     * @param pos Absolute position.
-     * @return Field value.
      * @throws BinaryObjectException In case of error.
      */
-    @Nullable Object unmarshalFieldByAbsolutePosition(int pos) throws BinaryObjectException {
-        parseHeaderIfNeeded();
-
-        in.position(pos);
-
-        return unmarshal();
+    @Nullable Object unmarshalField(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? unmarshal() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException On case of error.
      */
-    @Nullable Byte readByte(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(BYTE) == Flag.NULL)
-                return null;
+    @Nullable Map.Entry<?, ?> readMapEntry(int fieldId) throws BinaryObjectException {
+        if (findFieldById(fieldId)) {
+            Flag flag = checkFlag(MAP_ENTRY);
 
-            return in.readByte();
+            if (flag == Flag.NORMAL)
+                return doReadMapEntry(true);
+            else if (flag == Flag.HANDLE)
+                return readHandleField();
         }
-        else
-            return null;
+
+        return null;
     }
 
     /**
      * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @return Portable object.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Short readShort(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(SHORT) == Flag.NULL)
+    @Nullable BinaryObject readPortableObject(int fieldId) throws BinaryObjectException {
+        if (findFieldById(fieldId)) {
+            if (checkFlag(PORTABLE_OBJ) == Flag.NULL)
                 return null;
 
-            return in.readShort();
+            return new BinaryObjectImpl(ctx, doReadByteArray(), in.readInt());
         }
         else
             return null;
@@ -365,1100 +348,1038 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @return Field class.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Integer readInt(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(INT) == Flag.NULL)
+    @Nullable Class<?> readClass(int fieldId) throws BinaryObjectException {
+        if (findFieldById(fieldId)) {
+            if (checkFlag(CLASS) == Flag.NULL)
                 return null;
 
-            return in.readInt();
+            return doReadClass();
         }
-        else
-            return null;
+
+        return null;
     }
 
     /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @param obj Object.
      */
-    @Nullable Long readLong(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(LONG) == Flag.NULL)
-                return null;
-
-            return in.readLong();
-        }
-        else
-            return null;
+    void setHandler(Object obj) {
+        rCtx.put(start, obj);
     }
 
     /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @param obj Object.
+     * @param pos Position.
      */
-    @Nullable Float readFloat(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(FLOAT) == Flag.NULL)
-                return null;
-
-            return in.readFloat();
-        }
-        else
-            return null;
+    void setHandler(Object obj, int pos) {
+        rCtx.put(pos, obj);
     }
 
     /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * Recreating field value from a handle.
+     *
+     * @param <T> Field type.
+     * @return Field.
      */
-    @Nullable Double readDouble(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(DOUBLE) == Flag.NULL)
-                return null;
+    private <T> T readHandleField() {
+        int handle = (in.position() - 1) - in.readInt();
 
-            return in.readDouble();
-        }
-        else
-            return null;
-    }
+        int retPos = in.position();
 
-    /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable Character readChar(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(CHAR) == Flag.NULL)
-                return null;
+        Object obj = rCtx.get(handle);
+
+        if (obj == null) {
+            in.position(handle);
+
+            obj = doReadObject();
 
-            return in.readChar();
+            in.position(retPos);
         }
-        else
-            return null;
+
+        return (T)obj;
+    }
+    /** {@inheritDoc} */
+    @Override public byte readByte(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable Boolean readBoolean(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(BOOLEAN) == Flag.NULL)
-                return null;
-
-            return in.readBoolean();
-        }
-        else
-            return null;
+    byte readByte(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable BigDecimal readDecimal(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(DECIMAL) == Flag.NULL)
-                return null;
+    @Nullable Byte readByteNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : null;
+    }
 
-            return doReadDecimal();
-        }
-        else
-            return null;
+    /** {@inheritDoc} */
+    @Override public byte readByte() throws BinaryObjectException {
+        return in.readByte();
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public byte[] readByteArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readByteArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable String readString(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(STRING) == Flag.NULL)
-                return null;
+    @Nullable byte[] readByteArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readByteArray() : null;
+    }
 
-            return doReadString();
+    /** {@inheritDoc} */
+    @Nullable @Override public byte[] readByteArray() throws BinaryObjectException {
+        switch (checkFlag(BYTE_ARR)) {
+            case NORMAL:
+                return doReadByteArray();
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
         }
-        else
-            return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readBoolean(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL && in.readBoolean();
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable UUID readUuid(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(UUID) == Flag.NULL)
-                return null;
-
-            return doReadUuid();
-        }
-        else
-            return null;
+    boolean readBoolean(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL && in.readBoolean();
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Date readDate(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(DATE) == Flag.NULL)
-                return null;
+    @Nullable Boolean readBooleanNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL ? in.readBoolean() : null;
+    }
 
-            return doReadDate();
-        }
-        else
-            return null;
+    /** {@inheritDoc} */
+    @Override public boolean readBoolean() throws BinaryObjectException {
+        return in.readBoolean();
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public boolean[] readBooleanArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readBooleanArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Timestamp readTimestamp(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(TIMESTAMP) == Flag.NULL)
-                return null;
+    @Nullable boolean[] readBooleanArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readBooleanArray() : null;
+    }
 
-            return doReadTimestamp();
+    /** {@inheritDoc} */
+    @Nullable @Override public boolean[] readBooleanArray() throws BinaryObjectException {
+        switch (checkFlag(BOOLEAN_ARR)) {
+            case NORMAL:
+                return doReadBooleanArray();
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
         }
-        else
-            return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public short readShort(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable Object readObject(int fieldId) throws BinaryObjectException {
-        return hasField(fieldId) ? doReadObject() : null;
+    short readShort(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable byte[] readByteArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(BYTE_ARR);
+    @Nullable Short readShortNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : null;
+    }
 
-            if (flag == Flag.NORMAL)
-                return doReadByteArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
+    /** {@inheritDoc} */
+    @Override public short readShort() throws BinaryObjectException {
+        return in.readShort();
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Nullable @Override public short[] readShortArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readShortArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable short[] readShortArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(SHORT_ARR);
+        return findFieldById(fieldId) ? this.readShortArray() : null;
+    }
 
-            if (flag == Flag.NORMAL)
+    /** {@inheritDoc} */
+    @Nullable @Override public short[] readShortArray() throws BinaryObjectException {
+        switch (checkFlag(SHORT_ARR)) {
+            case NORMAL:
                 return doReadShortArray();
-            else if (flag == Flag.HANDLE)
+
+            case HANDLE:
                 return readHandleField();
+
+            default:
+                return null;
         }
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Override public char readChar(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable int[] readIntArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(INT_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadIntArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    char readChar(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable long[] readLongArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(LONG_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadLongArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
+    @Nullable Character readCharNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : null;
+    }
 
-        return null;
-    }
-
-    /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable float[] readFloatArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(FLOAT_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadFloatArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    /** {@inheritDoc} */
+    @Override public char readChar() throws BinaryObjectException {
+        return in.readChar();
     }
 
-    /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable double[] readDoubleArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(DOUBLE_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadDoubleArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    /** {@inheritDoc} */
+    @Nullable @Override public char[] readCharArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readCharArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable char[] readCharArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(CHAR_ARR);
+        return findFieldById(fieldId) ? this.readCharArray() : null;
+    }
 
-            if (flag == Flag.NORMAL)
+    /** {@inheritDoc} */
+    @Nullable @Override public char[] readCharArray() throws BinaryObjectException {
+        switch (checkFlag(CHAR_ARR)) {
+            case NORMAL:
                 return doReadCharArray();
-            else if (flag == Flag.HANDLE)
+
+            case HANDLE:
                 return readHandleField();
+
+            default:
+                return null;
         }
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Override public int readInt(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable boolean[] readBooleanArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(BOOLEAN_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadBooleanArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    int readInt(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable BigDecimal[] readDecimalArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(DECIMAL_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadDecimalArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
+    @Nullable Integer readIntNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : null;
+    }
+    
+    /** {@inheritDoc} */
+    @Override public int readInt() throws BinaryObjectException {
+        return in.readInt();
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Nullable @Override public int[] readIntArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readIntArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable String[] readStringArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(STRING_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadStringArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    @Nullable int[] readIntArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readIntArray() : null;
     }
 
-    /**
-     * @param fieldId Field ID.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable UUID[] readUuidArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(UUID_ARR);
+    /** {@inheritDoc} */
+    @Nullable @Override public int[] readIntArray() throws BinaryObjectException {
+        switch (checkFlag(INT_ARR)) {
+            case NORMAL:
+                return doReadIntArray();
 
-            if (flag == Flag.NORMAL)
-                return doReadUuidArray();
-            else if (flag == Flag.HANDLE)
+            case HANDLE:
                 return readHandleField();
+
+            default:
+                return null;
         }
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Override public long readLong(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable Date[] readDateArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(DATE_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadDateArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    long readLong(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Timestamp[] readTimestampArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(TIMESTAMP_ARR);
+    @Nullable Long readLongNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : null;
+    }
 
-            if (flag == Flag.NORMAL)
-                return doReadTimestampArray();
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
+    /** {@inheritDoc} */
+    @Override public long readLong() throws BinaryObjectException {
+        return in.readLong();
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Nullable @Override public long[] readLongArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readLongArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Object[] readObjectArray(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(OBJ_ARR);
-
-            if (flag == Flag.NORMAL)
-                return doReadObjectArray(true);
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    @Nullable long[] readLongArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readLongArray() : null;
     }
 
-    /**
-     * @param fieldId Field ID.
-     * @param cls Collection class.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable <T> Collection<T> readCollection(int fieldId, @Nullable Class<? extends Collection> cls)
-        throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(COL);
+    /** {@inheritDoc} */
+    @Nullable @Override public long[] readLongArray() throws BinaryObjectException {
+        switch (checkFlag(LONG_ARR)) {
+            case NORMAL:
+                return doReadLongArray();
 
-            if (flag == Flag.NORMAL)
-                return (Collection<T>)doReadCollection(true, cls);
-            else if (flag == Flag.HANDLE)
+            case HANDLE:
                 return readHandleField();
+
+            default:
+                return null;
         }
+    }
 
-        return null;
+    /** {@inheritDoc} */
+    @Override public float readFloat(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : 0;
     }
 
     /**
      * @param fieldId Field ID.
-     * @param cls Map class.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException If failed.
      */
-    @Nullable Map<?, ?> readMap(int fieldId, @Nullable Class<? extends Map> cls)
-        throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(MAP);
-
-            if (flag == Flag.NORMAL)
-                return doReadMap(true, cls);
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    float readFloat(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : 0;
     }
 
     /**
      * @param fieldId Field ID.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException On case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Map.Entry<?, ?> readMapEntry(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(MAP_ENTRY);
-
-            if (flag == Flag.NORMAL)
-                return doReadMapEntry(true);
-            else if (flag == Flag.HANDLE)
-                return readHandleField();
-        }
-
-        return null;
+    @Nullable Float readFloatNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : null;
     }
 
-    /**
-     * @param fieldId Field ID.
-     * @return Portable object.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable BinaryObject readPortableObject(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(PORTABLE_OBJ) == Flag.NULL)
-                return null;
-
-            return new BinaryObjectImpl(ctx, doReadByteArray(), in.readInt());
-        }
-        else
-            return null;
+    /** {@inheritDoc} */
+    @Override public float readFloat() throws BinaryObjectException {
+        return in.readFloat();
     }
 
-    /**
-     * @param fieldId Field ID.
-     * @param cls Class.
-     * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable Enum<?> readEnum(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(ENUM) == Flag.NULL)
-                return null;
-
-            // Revisit: why have we started writing Class for enums in their serialized form?
-            if (cls == null)
-                cls = doReadClass();
-            else
-                doReadClass();
-
-            Object[] vals = GridEnumCache.get(cls);
-
-            return (Enum<?>)vals[in.readInt()];
-        }
-        else
-            return null;
+    /** {@inheritDoc} */
+    @Nullable @Override public float[] readFloatArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readFloatArray() : null;
     }
 
     /**
      * @param fieldId Field ID.
-     * @param cls Class.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
-    @Nullable Object[] readEnumArray(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            Flag flag = checkFlag(ENUM_ARR);
+    @Nullable float[] readFloatArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readFloatArray() : null;
+    }
 
-            if (flag == Flag.NORMAL) {
-                if (cls == null)
-                    cls = doReadClass();
-                else
-                    doReadClass();
+    /** {@inheritDoc} */
+    @Nullable @Override public float[] readFloatArray() throws BinaryObjectException {
+        switch (checkFlag(FLOAT_ARR)) {
+            case NORMAL:
+                return doReadFloatArray();
 
-                return doReadEnumArray(cls);
-            }
-            else if (flag == Flag.HANDLE)
+            case HANDLE:
                 return readHandleField();
-        }
-
-        return null;
-    }
 
-    /**
-     * @param fieldId Field ID.
-     * @return Field class.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
-     */
-    @Nullable Class<?> readClass(int fieldId) throws BinaryObjectException {
-        if (hasField(fieldId)) {
-            if (checkFlag(CLASS) == Flag.NULL)
+            default:
                 return null;
-
-            return doReadClass();
         }
-
-        return null;
     }
 
-    /**
-     * @param obj Object.
-     */
-    void setHandler(Object obj) {
-        rCtx.setObjectHandler(start, obj);
+    /** {@inheritDoc} */
+    @Override public double readDouble(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : 0;
     }
 
     /**
-     * @param obj Object.
-     * @param pos Position.
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException If failed.
      */
-    void setHandler(Object obj, int pos) {
-        rCtx.setObjectHandler(pos, obj);
+    double readDouble(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : 0;
     }
 
     /**
-     * Recreating field value from a handle.
-     *
-     * @param <T> Field type.
-     * @return Field.
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
      */
-    private <T> T readHandleField() {
-        int handle = (in.position() - 1) - in.readInt();
-
-        Object obj = rCtx.getObjectByHandle(handle);
-
-        if (obj == null) {
-            in.position(handle);
-
-            obj = doReadObject();
-        }
-
-        return (T)obj;
-    }
-    /** {@inheritDoc} */
-    @Override public byte readByte(String fieldName) throws BinaryObjectException {
-        Byte val = readByte(fieldId(fieldName));
-
-        return val != null ? val : 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override public byte readByte() throws BinaryObjectException {
-        return in.readByte();
+    @Nullable Double readDoubleNullable(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public short readShort(String fieldName) throws BinaryObjectException {
-        Short val = readShort(fieldId(fieldName));
-
-        return val != null ? val : 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override public short readShort() throws BinaryObjectException {
-        return in.readShort();
+    @Override public double readDouble() throws BinaryObjectException {
+        return in.readDouble();
     }
 
     /** {@inheritDoc} */
-    @Override public int readInt(String fieldName) throws BinaryObjectException {
-        Integer val = readInt(fieldId(fieldName));
-
-        return val != null ? val : 0;
+    @Nullable @Override public double[] readDoubleArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDoubleArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Override public int readInt() throws BinaryObjectException {
-        return in.readInt();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable double[] readDoubleArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readDoubleArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public long readLong(String fieldName) throws BinaryObjectException {
-        Long val = readLong(fieldId(fieldName));
+    @Nullable @Override public double[] readDoubleArray() throws BinaryObjectException {
+        switch (checkFlag(DOUBLE_ARR)) {
+            case NORMAL:
+                return doReadDoubleArray();
 
-        return val != null ? val : 0;
-    }
+            case HANDLE:
+                return readHandleField();
 
-    /** {@inheritDoc} */
-    @Override public long readLong() throws BinaryObjectException {
-        return in.readLong();
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Override public float readFloat(String fieldName) throws BinaryObjectException {
-        Float val = readFloat(fieldId(fieldName));
-
-        return val != null ? val : 0;
+    @Override @Nullable public BigDecimal readDecimal(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDecimal() : null;
     }
 
-    /** {@inheritDoc} */
-    @Override public float readFloat() throws BinaryObjectException {
-        return in.readFloat();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable BigDecimal readDecimal(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readDecimal() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public double readDouble(String fieldName) throws BinaryObjectException {
-        Double val = readDouble(fieldId(fieldName));
-
-        return val != null ? val : 0;
+    @Override @Nullable public BigDecimal readDecimal() throws BinaryObjectException {
+        return checkFlagNoHandles(DECIMAL) == Flag.NORMAL ? doReadDecimal() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public double readDouble() throws BinaryObjectException {
-        return in.readDouble();
+    @Override @Nullable public BigDecimal[] readDecimalArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDecimalArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Override public char readChar(String fieldName) throws BinaryObjectException {
-        Character val = readChar(fieldId(fieldName));
-
-        return val != null ? val : 0;
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable BigDecimal[] readDecimalArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readDecimalArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public char readChar() throws BinaryObjectException {
-        return in.readChar();
-    }
+    @Override @Nullable public BigDecimal[] readDecimalArray() throws BinaryObjectException {
+        switch (checkFlag(DECIMAL_ARR)) {
+            case NORMAL:
+                return doReadDecimalArray();
 
-    /** {@inheritDoc} */
-    @Override public boolean readBoolean(String fieldName) throws BinaryObjectException {
-        Boolean val = readBoolean(fieldId(fieldName));
+            case HANDLE:
+                return readHandleField();
 
-        return val != null ? val : false;
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Override public boolean readBoolean() throws BinaryObjectException {
-        return in.readBoolean();
+    @Override @Nullable public String readString(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readString() : null;
     }
 
-    /** {@inheritDoc} */
-    @Override @Nullable public BigDecimal readDecimal(String fieldName) throws BinaryObjectException {
-        return readDecimal(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable String readString(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readString() : null;
     }
 
     /** {@inheritDoc} */
-    @Override @Nullable public BigDecimal readDecimal() throws BinaryObjectException {
-        if (checkFlag(DECIMAL) == Flag.NULL)
-            return null;
-
-        return doReadDecimal();
+    @Override @Nullable public String readString() throws BinaryObjectException {
+        return checkFlagNoHandles(STRING) == Flag.NORMAL ? doReadString() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public String readString(String fieldName) throws BinaryObjectException {
-        return readString(fieldId(fieldName));
+    @Override @Nullable public String[] readStringArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readStringArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public String readString() throws BinaryObjectException {
-        if (checkFlag(STRING) == Flag.NULL)
-            return null;
-
-        return doReadString();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable String[] readStringArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readStringArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public UUID readUuid(String fieldName) throws BinaryObjectException {
-        return readUuid(fieldId(fieldName));
-    }
+    @Override @Nullable public String[] readStringArray() throws BinaryObjectException {
+        switch (checkFlag(STRING_ARR)) {
+            case NORMAL:
+                return doReadStringArray();
 
-    /** {@inheritDoc} */
-    @Nullable @Override public UUID readUuid() throws BinaryObjectException {
-        if (checkFlag(UUID) == Flag.NULL)
-            return null;
+            case HANDLE:
+                return readHandleField();
 
-        return doReadUuid();
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Date readDate(String fieldName) throws BinaryObjectException {
-        return readDate(fieldId(fieldName));
+    @Override @Nullable public UUID readUuid(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readUuid() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public Date readDate() throws BinaryObjectException {
-        if (checkFlag(DATE) == Flag.NULL)
-            return null;
-
-        return doReadDate();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable UUID readUuid(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readUuid() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Timestamp readTimestamp(String fieldName) throws BinaryObjectException {
-        return readTimestamp(fieldId(fieldName));
+    @Override @Nullable public UUID readUuid() throws BinaryObjectException {
+        return checkFlagNoHandles(UUID) == Flag.NORMAL ? doReadUuid() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Timestamp readTimestamp() throws BinaryObjectException {
-        if (checkFlag(TIMESTAMP) == Flag.NULL)
-            return null;
-
-        return doReadTimestamp();
+    @Override @Nullable public UUID[] readUuidArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readUuidArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
-    @Nullable @Override public <T> T readObject(String fieldName) throws BinaryObjectException {
-        return (T)readObject(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable UUID[] readUuidArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readUuidArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Override public Object readObject() throws BinaryObjectException {
-        return doReadObject();
-    }
+    @Override @Nullable public UUID[] readUuidArray() throws BinaryObjectException {
+        switch (checkFlag(UUID_ARR)) {
+            case NORMAL:
+                return doReadUuidArray();
 
-    /** {@inheritDoc} */
-    @Nullable @Override public Object readObjectDetached() throws BinaryObjectException {
-        return unmarshal(true);
-    }
+            case HANDLE:
+                return readHandleField();
 
-    /** {@inheritDoc} */
-    @Nullable @Override public byte[] readByteArray(String fieldName) throws BinaryObjectException {
-        return readByteArray(fieldId(fieldName));
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public byte[] readByteArray() throws BinaryObjectException {
-        if (checkFlag(BYTE_ARR) == Flag.NULL)
-            return null;
-
-        return doReadByteArray();
+    @Override @Nullable public Date readDate(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDate() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public short[] readShortArray(String fieldName) throws BinaryObjectException {
-        return readShortArray(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Date readDate(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readDate() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public short[] readShortArray() throws BinaryObjectException {
-        if (checkFlag(SHORT_ARR) == Flag.NULL)
-            return null;
-
-        return doReadShortArray();
+    @Override @Nullable public Date readDate() throws BinaryObjectException {
+        return checkFlagNoHandles(DATE) == Flag.NORMAL ? doReadDate() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public int[] readIntArray(String fieldName) throws BinaryObjectException {
-        return readIntArray(fieldId(fieldName));
+    @Override @Nullable public Date[] readDateArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDateArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public int[] readIntArray() throws BinaryObjectException {
-        if (checkFlag(INT_ARR) == Flag.NULL)
-            return null;
-
-        return doReadIntArray();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Date[] readDateArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readDateArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public long[] readLongArray(String fieldName) throws BinaryObjectException {
-        return readLongArray(fieldId(fieldName));
-    }
+    @Override @Nullable public Date[] readDateArray() throws BinaryObjectException {
+        switch (checkFlag(DATE_ARR)) {
+            case NORMAL:
+                return doReadDateArray();
 
-    /** {@inheritDoc} */
-    @Nullable @Override public long[] readLongArray() throws BinaryObjectException {
-        if (checkFlag(LONG_ARR) == Flag.NULL)
-            return null;
+            case HANDLE:
+                return readHandleField();
 
-        return doReadLongArray();
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public float[] readFloatArray(String fieldName) throws BinaryObjectException {
-        return readFloatArray(fieldId(fieldName));
+    @Override @Nullable public Timestamp readTimestamp(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readTimestamp() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public float[] readFloatArray() throws BinaryObjectException {
-        if (checkFlag(FLOAT_ARR) == Flag.NULL)
-            return null;
-
-        return doReadFloatArray();
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Timestamp readTimestamp(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readTimestamp() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public double[] readDoubleArray(String fieldName) throws BinaryObjectException {
-        return readDoubleArray(fieldId(fieldName));
+    @Override @Nullable public Timestamp readTimestamp() throws BinaryObjectException {
+        return checkFlagNoHandles(TIMESTAMP) == Flag.NORMAL ? doReadTimestamp() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public double[] readDoubleArray() throws BinaryObjectException {
-        if (checkFlag(DOUBLE_ARR) == Flag.NULL)
-            return null;
-
-        return doReadDoubleArray();
+    @Override @Nullable public Timestamp[] readTimestampArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readTimestampArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public char[] readCharArray(String fieldName) throws BinaryObjectException {
-        return readCharArray(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Timestamp[] readTimestampArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readTimestampArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public char[] readCharArray() throws BinaryObjectException {
-        if (checkFlag(CHAR_ARR) == Flag.NULL)
-            return null;
+    @Override @Nullable public Timestamp[] readTimestampArray() throws BinaryObjectException {
+        switch (checkFlag(TIMESTAMP_ARR)) {
+            case NORMAL:
+                return doReadTimestampArray();
 
-        return doReadCharArray();
-    }
+            case HANDLE:
+                return readHandleField();
 
-    /** {@inheritDoc} */
-    @Nullable @Override public boolean[] readBooleanArray(String fieldName) throws BinaryObjectException {
-        return readBooleanArray(fieldId(fieldName));
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public boolean[] readBooleanArray() throws BinaryObjectException {
-        if (checkFlag(BOOLEAN_ARR) == Flag.NULL)
-            return null;
-
-        return doReadBooleanArray();
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T readObject(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (T)doReadObject() : null;
     }
 
-    /** {@inheritDoc} */
-    @Override @Nullable public BigDecimal[] readDecimalArray(String fieldName) throws BinaryObjectException {
-        return readDecimalArray(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Object readObject(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? doReadObject() : null;
     }
 
     /** {@inheritDoc} */
-    @Override @Nullable public BigDecimal[] readDecimalArray() throws BinaryObjectException {
-        if (checkFlag(DECIMAL_ARR) == Flag.NULL)
-            return null;
-
-        return doReadDecimalArray();
+    @Override public Object readObject() throws BinaryObjectException {
+        return doReadObject();
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public String[] readStringArray(String fieldName) throws BinaryObjectException {
-        return readStringArray(fieldId(fieldName));
+    @Nullable @Override public Object readObjectDetached() throws BinaryObjectException {
+        return unmarshal(true);
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public String[] readStringArray() throws BinaryObjectException {
-        if (checkFlag(STRING_ARR) == Flag.NULL)
-            return null;
-
-        return doReadStringArray();
+    @Nullable @Override public Object[] readObjectArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readObjectArray() : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public UUID[] readUuidArray(String fieldName) throws BinaryObjectException {
-        return readUuidArray(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Object[] readObjectArray(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? this.readObjectArray() : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public UUID[] readUuidArray() throws BinaryObjectException {
-        if (checkFlag(UUID_ARR) == Flag.NULL)
-            return null;
+    @Nullable @Override public Object[] readObjectArray() throws BinaryObjectException {
+        switch (checkFlag(OBJ_ARR)) {
+            case NORMAL:
+                return doReadObjectArray(true);
 
-        return doReadUuidArray();
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Date[] readDateArray(String fieldName) throws BinaryObjectException {
-        return readDateArray(fieldId(fieldName));
+    @Nullable @Override public <T extends Enum<?>> T readEnum(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (T)readEnum0(null) : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public Timestamp[] readTimestampArray(String fieldName) throws BinaryObjectException {
-        return readTimestampArray(fieldId(fieldName));
+    /**
+     * @param fieldId Field ID.
+     * @param cls Class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Enum<?> readEnum(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
+        return findFieldById(fieldId) ? readEnum0(cls) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Date[] readDateArray() throws BinaryObjectException {
-        if (checkFlag(DATE_ARR) == Flag.NULL)
-            return null;
+    @Nullable @Override public <T extends Enum<?>> T readEnum() throws BinaryObjectException {
+        return (T)readEnum0(null);
+    }
+
+    /**
+     * Internal routine to read enum for named field.
+     *
+     * @param cls Class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    private Enum<?> readEnum0(@Nullable Class<?> cls) throws BinaryObjectException {
+        if (checkFlagNoHandles(ENUM) == Flag.NORMAL) {
+            // Read class even if we know it in advance to set correct stream position.
+            Class<?> cls0 = doReadClass();
 
-        return doReadDateArray();
+            if (cls == null)
+                cls = cls0;
+
+            return doReadEnum(cls);
+        }
+        else
+            return null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Timestamp[] readTimestampArray() throws BinaryObjectException {
-        if (checkFlag(TIMESTAMP_ARR) == Flag.NULL)
-            return null;
+    @Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName)
+        throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (T[])readEnumArray0(null) : null;
+    }
 
-        return doReadTimestampArray();
+    /**
+     * @param fieldId Field ID.
+     * @param cls Class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Object[] readEnumArray(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
+        return findFieldById(fieldId) ? readEnumArray0(cls) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public Object[] readObjectArray(String fieldName) throws BinaryObjectException {
-        return readObjectArray(fieldId(fieldName));
+    @Nullable @Override public <T extends Enum<?>> T[] readEnumArray() throws BinaryObjectException {
+        return (T[])readEnumArray0(null);
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public Object[] readObjectArray() throws BinaryObjectException {
-        if (checkFlag(OBJ_ARR) == Flag.NULL)
-            return null;
+    /**
+     * Internal routine to read enum for named field.
+     *
+     * @param cls Class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    private Object[] readEnumArray0(@Nullable Class<?> cls) throws BinaryObjectException {
+        switch (checkFlag(ENUM_ARR)) {
+            case NORMAL:
+                // Read class even if we know it in advance to set correct stream position.
+                Class<?> cls0 = doReadClass();
+
+                if (cls == null)
+                    cls = cls0;
+
+                return doReadEnumArray(cls);
+
+            case HANDLE:
+                return readHandleField();
 
-        return doReadObjectArray(true);
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T> Collection<T> readCollection(String fieldName) throws BinaryObjectException {
-        return readCollection(fieldId(fieldName), null);
+        return findFieldByName(fieldName) ? (Collection<T>)readCollection0(null) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <T> Collection<T> readCollection() throws BinaryObjectException {
-        if (checkFlag(COL) == Flag.NULL)
-            return null;
+    @Nullable @Override public <T> Collection<T> readCollection(String fieldName,
+        Class<? extends Collection<T>> colCls) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? readCollection0(colCls) : null;
+    }
 
-        return (Collection<T>)doReadCollection(true, null);
+    /**
+     * @param fieldId Field ID.
+     * @param colCls Collection class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable <T> Collection<T> readCollection(int fieldId, @Nullable Class<? extends Collection> colCls)
+        throws BinaryObjectException {
+        return findFieldById(fieldId) ? (Collection<T>)readCollection0(colCls) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <T> Collection<T> readCollection(String fieldName,
-        Class<? extends Collection<T>> colCls) throws BinaryObjectException {
-        return readCollection(fieldId(fieldName), colCls);
+    @Nullable @Override public <T> Collection<T> readCollection() throws BinaryObjectException {
+        return readCollection0(null);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T> Collection<T> readCollection(Class<? extends Collection<T>> colCls)
         throws BinaryObjectException {
-        if (checkFlag(COL) == Flag.NULL)
-            return null;
-
-        return (Collection<T>)doReadCollection(true, colCls);
+        return readCollection0(colCls);
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName) throws BinaryObjectException {
-        return (Map<K, V>)readMap(fieldId(fieldName), null);
-    }
+    /**
+     * Internal read collection routine.
+     *
+     * @param cls Collection class.
+     * @return Value.
+     * @throws BinaryObjectException If failed.
+     */
+    private Collection readCollection0(@Nullable Class<? extends Collection> cls)
+        throws BinaryObjectException {
+        switch (checkFlag(COL)) {
+            case NORMAL:
+                return (Collection)doReadCollection(true, cls);
 
-    /** {@inheritDoc} */
-    @Nullable @Override public <K, V> Map<K, V> readMap() throws BinaryObjectException {
-        if (checkFlag(MAP) == Flag.NULL)
-            return null;
+            case HANDLE:
+                return readHandleField();
 
-        return (Map<K, V>)doReadMap(true, null);
+            default:
+                return null;
+        }
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName, Class<? extends Map<K, V>> mapCls)
-        throws BinaryObjectException {
-        return (Map<K, V>)readMap(fieldId(fieldName), mapCls);
+    @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (Map<K, V>)readMap0(null) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <K, V> Map<K, V> readMap(Class<? extends Map<K, V>> mapCls)
+    @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName, Class<? extends Map<K, V>> mapCls)
         throws BinaryObjectException {
-        if (checkFlag(MAP) == Flag.NULL)
-            return null;
-
-        return (Map<K, V>)doReadMap(true, mapCls);
+        return findFieldByName(fieldName) ? readMap0(mapCls) : null;
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public <T extends Enum<?>> T readEnum(String fieldName)
-        throws BinaryObjectException {
-        return (T)readEnum(fieldId(fieldName), null);
+    /**
+     * @param fieldId Field ID.
+     * @param mapCls Map class.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Map<?, ?> readMap(int fieldId, @Nullable Class<? extends Map> mapCls) throws BinaryObjectException {
+        return findFieldById(fieldId) ? readMap0(mapCls) : null;
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <T extends Enum<?>> T readEnum() throws BinaryObjectException {
-        if (checkFlag(ENUM) == Flag.NULL)
-            return null;
-
-        Class cls = doReadClass();
-
-        return (T)doReadEnum(cls);
+    @Nullable @Override public <K, V> Map<K, V> readMap() throws BinaryObjectException {
+        return readMap0(null);
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName)
+    @Nullable @Override public <K, V> Map<K, V> readMap(Class<? extends Map<K, V>> mapCls)
         throws BinaryObjectException {
-        return (T[])readEnumArray(fieldId(fieldName), null);
+        return readMap0(mapCls);
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override public <T extends Enum<?>> T[] readEnumArray() throws BinaryObjectException {
-        if (checkFlag(ENUM_ARR) == Flag.NULL)
-            return null;
+    /**
+     * Internal read map routine.
+     *
+     * @param cls Map class.
+     * @return Value.
+     * @throws BinaryObjectException If failed.
+     */
+    private Map readMap0(@Nullable Class<? extends Map> cls) throws BinaryObjectException {
+        switch (checkFlag(MAP)) {
+            case NORMAL:
+                return (Map)doReadMap(true, cls);
 
-        Class cls = doReadClass();
+            case HANDLE:
+                return readHandleField();
 
-        return (T[])doReadEnumArray(cls);
+            default:
+                return null;
+        }
     }
 
     /**
-     * Ensure that type flag is either null or contains expected value.
+     * Ensure that type flag is either null, handle or contains expected value.
      *
      * @param expFlag Expected value.
-     * @return Flag.
-     * @throws org.apache.ignite.binary.BinaryObjectException If flag is neither null, nor expected.
+     * @return Flag mode.
+     * @throws BinaryObjectException If flag is neither null, nor handle or expected.
      */
     private Flag checkFlag(byte expFlag) {
         byte flag = in.readByte();
 
-        if (flag == NULL)
+        if (flag == expFlag)
+            return Flag.NORMAL;
+        else if (flag == NULL)
             return Flag.NULL;
         else if (flag == HANDLE)
             return Flag.HANDLE;
-        else if (flag != expFlag) {
-            int pos = in.position() - 1;
 
-            throw new BinaryObjectException("Unexpected flag value [pos=" + pos + ", expected=" + expFlag +
-                ", actual=" + flag + ']');
-        }
+        int pos = positionForHandle();
 
-        return Flag.NORMAL;
+        throw new BinaryObjectException("Unexpected flag value [pos=" + pos + ", expected=" + expFlag +
+            ", actual=" + flag + ']');
     }
 
     /**
-     * @param fieldName Field name.
-     * @return {@code True} if field is set.
+     * Ensure that type flag is either null or contains expected value.
+     *
+     * @param expFlag Expected value.
+     * @return Flag mode.
+     * @throws BinaryObjectException If flag is neither null, nor expected.
      */
-    public boolean hasField(String fieldName) {
-        return hasField(fieldId(fieldName));
+    private Flag checkFlagNoHandles(byte expFlag) {
+        byte flag = in.readByte();
+
+        if (flag == expFlag)
+            return Flag.NORMAL;
+        else if (flag == NULL)
+            return Flag.NULL;
+
+        int pos = positionForHandle();
+
+        throw new BinaryObjectException("Unexpected flag value [pos=" + pos + ", expected=" + expFlag +
+            ", actual=" + flag + ']');
     }
 
     /**
-     * @param fieldId Field ID.
+     * @param fieldName Field name.
      * @return {@code True} if field is set.
      */
-    private boolean hasField(int fieldId) {
-        return fieldOffset(fieldId) != 0;
+    public boolean hasField(String fieldName) {
+        return findFieldById(fieldId(fieldName));
     }
 
     /** {@inheritDoc} */
@@ -1470,7 +1391,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Unmarshalled value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable private Object unmarshal(boolean detach) throws BinaryObjectException {
         int start = in.position();
@@ -1484,7 +1405,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
             case HANDLE:
                 int handle = start - in.readInt();
 
-                BinaryObject handledPo = rCtx.getPortableByHandle(handle);
+                BinaryObject handledPo = rCtx.get(handle);
 
                 if (handledPo != null)
                     return handledPo;
@@ -1513,7 +1434,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
                         in.remaining() + in.position())
                         : new BinaryObjectImpl(ctx, in.array(), start);
 
-                rCtx.setPortableHandler(start, po);
+                rCtx.put(start, po);
 
                 in.position(start + po.length());
 
@@ -1672,7 +1593,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
         String res = new String(in.array(), strOff, strLen, UTF_8);
 
-        in.position(in.position() + strLen);
+        in.position(strOff + strLen);
 
         return res;
     }
@@ -1709,17 +1630,17 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Object.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @Nullable private Object doReadObject() throws BinaryObjectException {
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, in, in.position(), ldr, rCtx);
+        BinaryReaderExImpl reader = new BinaryReaderExImpl(ctx, in, ldr, rCtx);
 
         return reader.deserialize();
     }
 
     /**
      * @return Deserialized object.
-     * @throws org.apache.ignite.binary.BinaryObjectException If failed.
+     * @throws BinaryObjectException If failed.
      */
     @Nullable Object deserialize() throws BinaryObjectException {
         Object obj;
@@ -1735,7 +1656,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
             case HANDLE:
                 int handle = start - in.readInt();
 
-                obj = rCtx.getObjectByHandle(handle);
+                obj = rCtx.get(handle);
 
                 if (obj == null) {
                     int retPos = in.position();
@@ -1750,20 +1671,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
                 break;
 
             case OBJ:
-                parseHeaderIfNeeded();
-
-                assert typeId != UNREGISTERED_TYPE_ID;
-
-                PortableUtils.checkProtocolVersion(in.readByte());
-
-                boolean userType = PortableUtils.isUserType(this.readShort());
-
-                // Skip typeId and hash code.
-                in.position(in.position() + 8);
-
-                desc = ctx.descriptorForTypeId(userType, typeId, ldr);
-
-                int len = in.readInt();
+                PortableClassDescriptor desc = ctx.descriptorForTypeId(userType, typeId, ldr);
 
                 in.position(start + hdrLen);
 
@@ -1772,7 +1680,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
                 obj = desc.read(this);
 
-                in.position(start + len);
+                in.position(footerStart + footerLen);
 
                 break;
 
@@ -1978,7 +1886,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private byte[] doReadByteArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -1993,7 +1901,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private short[] doReadShortArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2008,7 +1916,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private int[] doReadIntArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2023,7 +1931,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private long[] doReadLongArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2038,7 +1946,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private float[] doReadFloatArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2053,7 +1961,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private double[] doReadDoubleArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2068,7 +1976,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private char[] doReadCharArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2083,7 +1991,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Value.
      */
     private boolean[] doReadBooleanArray() {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2096,10 +2004,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private BigDecimal[] doReadDecimalArray() throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2125,10 +2033,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private String[] doReadStringArray() throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2151,13 +2059,13 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
         return arr;
     }
-
+    
     /**
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private UUID[] doReadUuidArray() throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2183,10 +2091,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private Date[] doReadDateArray() throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2212,10 +2120,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
 
     /**
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private Timestamp[] doReadTimestampArray() throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int len = in.readInt();
 
@@ -2242,10 +2150,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     /**
      * @param deep Deep flag.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private Object[] doReadObjectArray(boolean deep) throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         Class compType = doReadClass();
 
@@ -2265,12 +2173,12 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @param deep Deep flag.
      * @param cls Collection class.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @SuppressWarnings("unchecked")
     private Collection<?> doReadCollection(boolean deep, @Nullable Class<? extends Collection> cls)
         throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int size = in.readInt();
 
@@ -2353,12 +2261,12 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @param deep Deep flag.
      * @param cls Map class.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     @SuppressWarnings("unchecked")
     private Map<?, ?> doReadMap(boolean deep, @Nullable Class<? extends Map> cls)
         throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         int size = in.readInt();
 
@@ -2430,10 +2338,10 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     /**
      * @param deep Deep flag.
      * @return Value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+     * @throws BinaryObjectException In case of error.
      */
     private Map.Entry<?, ?> doReadMapEntry(boolean deep) throws BinaryObjectException {
-        int hPos = in.position() - 1;
+        int hPos = positionForHandle();
 
         Object val1 = deep ? doReadObject() : unmarshal();
         Object val2 = deep ? doReadObject() : unmarshal();
@@ -2469,16 +2377,20 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     }
 
     /**
+     * Having target class in place we simply read ordinal and create final representation.
+     *
      * @param cls Enum class.
      * @return Value.
      */
     private Enum<?> doReadEnum(Class<?> cls) throws BinaryObjectException {
+        assert cls != null;
+
         if (!cls.isEnum())
             throw new BinaryObjectException("Class does not represent enum type: " + cls.getName());
 
         int ord = in.readInt();
 
-        return ord >= 0 ? (Enum<?>)GridEnumCache.get(cls)[ord] : null;
+        return BinaryEnumCache.get(cls, ord);
     }
 
     /**
@@ -2544,19 +2456,21 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     }
 
     /**
+     * Get position to be used for handle. We assume here that the hdr byte was read, hence subtract -1.  
+     *
+     * @return Position for handle.
+     */
+    int positionForHandle() {
+        return in.position() - 1;
+    }
+    
+    /**
      * @param name Field name.
      * @return Field offset.
      */
     private int fieldId(String name) {
         assert name != null;
 
-        parseHeaderIfNeeded();
-
-        assert typeId != UNREGISTERED_TYPE_ID;
-
-        if (idMapper == null)
-            idMapper = ctx.userTypeIdMapper(typeId);
-
         return idMapper.fieldId(typeId, name);
     }
 
@@ -2566,8 +2480,6 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
      * @return Schema.
      */
     public PortableSchema getOrCreateSchema() {
-        parseHeaderIfNeeded();
-
         PortableSchema schema = ctx.schemaRegistry(typeId).schema(schemaId);
 
         if (schema == null) {
@@ -2626,71 +2538,162 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Obje
     }
 
     /**
-     * @param id Field ID.
-     * @return Field offset.
+     * Try finding the field by name.
+     *
+     * @param name Field name.
+     * @return Offset.
      */
-    private int fieldOffset(int id) {
+    private boolean findFieldByName(String name) {
         assert hdrLen != 0;
 
         if (footerLen == 0)
-            return 0;
+            return false;
 
-        int searchPos = footerStart;
-        int searchTail = searchPos + footerLen;
+        if (userType) {
+            int order;
 
-        if (!userType || (fieldIdLen != 0 && hasLowFieldsCount(footerLen))) {
-            while (true) {
-                if (searchPos >= searchTail)
-                    return 0;
+            if (matching) {
+                int expOrder = matchingOrder++;
 
-                int id0 = in.readIntPositioned(searchPos);
+                PortableSchema.Confirmation confirm = schema.confirmOrder(expOrder, name);
 
-                if (id0 == id) {
-                    int pos = start + PortableUtils.fieldOffsetRelative(in, searchPos + PortableUtils.FIELD_ID_LEN,
-                        fieldOffsetLen);
+                switch (confirm) {
+                    case CONFIRMED:
+                        // The best case: got order without ID calculation and (ID -> order) lookup.
+                        order = expOrder;
 
-                    in.position(pos);
+                        break;
 
-                    return pos;
-                }
+

<TRUNCATED>