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/03 11:15:29 UTC

[1/2] ignite git commit: IGNITE-1418: Implemented compact field offsets.

Repository: ignite
Updated Branches:
  refs/heads/ignite-1282 fd640d7a8 -> 845c4f272


http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp
index 57c23a7..448cf02 100644
--- a/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp
+++ b/modules/platforms/cpp/core/src/impl/portable/portable_schema.cpp
@@ -15,6 +15,8 @@
 * limitations under the License.
 */
 
+#include <cassert>
+
 #include "ignite/impl/portable/portable_schema.h"
 #include "ignite/impl/portable/portable_writer_impl.h"
 
@@ -66,10 +68,43 @@ namespace ignite
 
             void PortableSchema::Write(interop::InteropOutputStream& out) const
             {
-                for (FieldContainer::const_iterator i = fieldsInfo->begin(); i != fieldsInfo->end(); ++i)
+                switch (GetType())
                 {
-                    out.WriteInt32(i->id);
-                    out.WriteInt32(i->offset);
+                    case OFFSET_TYPE_1_BYTE:
+                    {
+                        for (FieldContainer::const_iterator i = fieldsInfo->begin(); i != fieldsInfo->end(); ++i)
+                        {
+                            out.WriteInt32(i->id);
+                            out.WriteInt8(static_cast<int8_t>(i->offset));
+                        }
+                        break;
+                    }
+
+                    case OFFSET_TYPE_2_BYTE:
+                    {
+                        for (FieldContainer::const_iterator i = fieldsInfo->begin(); i != fieldsInfo->end(); ++i)
+                        {
+                            out.WriteInt32(i->id);
+                            out.WriteInt16(static_cast<int16_t>(i->offset));
+                        }
+                        break;
+                    }
+
+                    case OFFSET_TYPE_4_BYTE:
+                    {
+                        for (FieldContainer::const_iterator i = fieldsInfo->begin(); i != fieldsInfo->end(); ++i)
+                        {
+                            out.WriteInt32(i->id);
+                            out.WriteInt32(i->offset);
+                        }
+                        break;
+                    }
+
+                    default:
+                    {
+                        assert(false);
+                        break;
+                    }
                 }
             }
 
@@ -83,6 +118,18 @@ namespace ignite
                 id = 0;
                 fieldsInfo->clear();
             }
+
+            PortableOffsetType PortableSchema::GetType() const
+            {
+                int32_t maxOffset = fieldsInfo->back().offset;
+
+                if (maxOffset < 0x100)
+                    return OFFSET_TYPE_1_BYTE;
+                else if (maxOffset < 0x10000)
+                    return OFFSET_TYPE_2_BYTE;
+
+                return OFFSET_TYPE_4_BYTE;
+            }
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp
index 4b65b4b..2dac125 100644
--- a/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/portable/portable_writer_impl.cpp
@@ -567,13 +567,12 @@ namespace ignite
             {
                 int32_t lenWithoutSchema = stream->Position() - start;
 
+                int32_t nonRawLen = rawPos == -1 ? lenWithoutSchema : rawPos - start;
+                
                 if (schema.Empty())
                 {
-                    InteropStreamPositionGuard<InteropOutputStream> guard(*stream);
-
-                    stream->Position(start + IGNITE_OFFSET_FLAGS);
-                    stream->WriteInt16(IGNITE_PORTABLE_FLAG_USER_OBJECT | IGNITE_PORTABLE_FLAG_RAW_ONLY);
-
+                    stream->WriteInt16(start + IGNITE_OFFSET_FLAGS, IGNITE_PORTABLE_FLAG_USER_OBJECT | 
+                                                                    IGNITE_PORTABLE_FLAG_RAW_ONLY);
                     stream->WriteInt32(start + IGNITE_OFFSET_LEN, lenWithoutSchema);
                     stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_ID, 0);
                     stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_OR_RAW_OFF, GetRawPosition() - start);
@@ -581,6 +580,7 @@ namespace ignite
                 else
                 {
                     int32_t schemaId = schema.GetId();
+                    PortableOffsetType schemaType = schema.GetType();
 
                     WriteAndClearSchema();
 
@@ -589,6 +589,17 @@ namespace ignite
 
                     int32_t length = stream->Position() - start;
 
+                    if (schemaType == OFFSET_TYPE_1_BYTE)
+                    {
+                        stream->WriteInt16(start + IGNITE_OFFSET_FLAGS, 
+                            IGNITE_PORTABLE_FLAG_USER_OBJECT | IGNITE_PORTABLE_FLAG_OFFSET_1_BYTE);
+                    }
+                    else if (schemaType == OFFSET_TYPE_2_BYTE)
+                    {
+                        stream->WriteInt16(start + IGNITE_OFFSET_FLAGS, 
+                            IGNITE_PORTABLE_FLAG_USER_OBJECT | IGNITE_PORTABLE_FLAG_OFFSET_2_BYTE);
+                    }
+
                     stream->WriteInt32(start + IGNITE_OFFSET_LEN, length);
                     stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_ID, schemaId);
                     stream->WriteInt32(start + IGNITE_OFFSET_SCHEMA_OR_RAW_OFF, lenWithoutSchema);

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs
index 08e0b31..2313f92 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Portable/PortableSelfTest.cs
@@ -1225,6 +1225,38 @@ namespace Apache.Ignite.Core.Tests.Portable
             Assert.AreEqual(nDateArr, obj2.NDateArr);
         }
 
+        /// <summary>
+        /// Writes objects of various sizes to test schema compaction 
+        /// (where field offsets can be stored as 1, 2 or 4 bytes).
+        /// </summary>
+        [Test]
+        public void TestCompactSchema()
+        {
+            var marsh = new PortableMarshaller(new PortableConfiguration
+            {
+                TypeConfigurations = new List<PortableTypeConfiguration>
+                {
+                    new PortableTypeConfiguration(typeof (SpecialArray)),
+                    new PortableTypeConfiguration(typeof (SpecialArrayMarshalAware))
+                }
+            });
+
+            var dt = new SpecialArrayMarshalAware();
+
+            foreach (var i in new[] {1, 5, 10, 13, 14, 15, 100, 200, 1000, 5000, 15000, 30000})
+            {
+                dt.NGuidArr = Enumerable.Range(1, i).Select(x => (Guid?) Guid.NewGuid()).ToArray();
+                dt.NDateArr = Enumerable.Range(1, i).Select(x => (DateTime?) DateTime.Now.AddDays(x)).ToArray();
+
+                var bytes = marsh.Marshal(dt);
+
+                var res = marsh.Unmarshal<SpecialArrayMarshalAware>(bytes);
+
+                CollectionAssert.AreEquivalent(dt.NGuidArr, res.NGuidArr);
+                CollectionAssert.AreEquivalent(dt.NDateArr, res.NDateArr);
+            }
+        }
+
         private static void CheckKeepSerialized(PortableConfiguration cfg, bool expKeep)
         {
             if (cfg.TypeConfigurations == null)

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs
index cb432e5..82a8eee 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/ResizeableArray.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * 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.
@@ -27,9 +27,6 @@ namespace Apache.Ignite.Core.Impl.Common
         /** Array. */
         private T[] _arr;
 
-        /** Items count. */
-        private int _count;
-
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -50,10 +47,7 @@ namespace Apache.Ignite.Core.Impl.Common
         /// <summary>
         /// Count.
         /// </summary>
-        public int Count
-        {
-            get { return _count; }
-        }
+        public int Count { get; private set; }
 
         /// <summary>
         /// Add element.
@@ -61,10 +55,10 @@ namespace Apache.Ignite.Core.Impl.Common
         /// <param name="element">Element.</param>
         public void Add(T element)
         {
-            if (_count == _arr.Length)
+            if (Count == _arr.Length)
                 System.Array.Resize(ref _arr, _arr.Length*2);
 
-            _arr[_count++] = element;
+            _arr[Count++] = element;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs
index ea109ba..c12a651 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs
@@ -21,7 +21,6 @@ namespace Apache.Ignite.Core.Impl
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
-    using System.Runtime.InteropServices;
     using System.Security;
     using System.Threading;
     using Apache.Ignite.Core.Cache;
@@ -35,7 +34,6 @@ namespace Apache.Ignite.Core.Impl
     /// <summary>
     /// Managed environment. Acts as a gateway for native code.
     /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
     internal static class ExceptionUtils
     {
         /** NoClassDefFoundError fully-qualified class name which is important during startup phase. */

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
index 08a1d00..c299039 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableBuilderImpl.cs
@@ -569,7 +569,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <param name="hash">New hash.</param>
         /// <param name="vals">Values to be replaced.</param>
         /// <returns>Mutated object.</returns>
-        private unsafe void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream,
+        private void Mutate0(Context ctx, PortableHeapStream inStream, IPortableStream outStream,
             bool changeHash, int hash, IDictionary<int, PortableBuilderField> vals)
         {
             int inStartPos = inStream.Position;
@@ -694,12 +694,14 @@ namespace Apache.Ignite.Core.Impl.Portable
 
                         // Write schema
                         int outSchemaOff = outRawOff;
+                        short flags = 0;
 
                         if (outSchema != null)
                         {
                             outSchemaOff = outStream.Position - outStartPos;
 
-                            PortableObjectSchemaField.WriteArray(outSchema.Array, outStream, outSchema.Count);
+                            flags = PortableObjectHeader.WriteSchema(outSchema.Array, outStream, outSchema.Count,
+                                outStream.Position - outStartPos);
 
                             if (inRawLen > 0)
                                 outStream.WriteInt(outRawOff);
@@ -712,7 +714,7 @@ namespace Apache.Ignite.Core.Impl.Portable
                         var outHash = changeHash ? hash : inHeader.HashCode;
 
                         var outHeader = new PortableObjectHeader(inHeader.IsUserType, inHeader.TypeId, outHash, 
-                            outLen, outSchemaId, outSchemaOff, outSchema == null);
+                            outLen, outSchemaId, outSchemaOff, outSchema == null, flags);
 
                         PortableObjectHeader.Write(outHeader, outStream, outStartPos);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs
index b3768a0..50adc02 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectHeader.cs
@@ -27,17 +27,23 @@ namespace Apache.Ignite.Core.Impl.Portable
     /// <summary>
     /// Portable object header structure.
     /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
+    [StructLayout(LayoutKind.Sequential, Pack = 0)]
     internal struct PortableObjectHeader : IEquatable<PortableObjectHeader>
     {
-        /** Size, equals to sizeof(PortableObjectHeader) */
+        /** Size, equals to sizeof(PortableObjectHeader). */
         public const int Size = 24;
 
-        /** User type flag */
-        private const int FlagUserType = 0x1;
+        /** User type flag. */
+        public const short FlagUserType = 0x1;
 
-        /** Raw only flag */
-        private const int FlagRawOnly = 0x2;
+        /** Raw only flag. */
+        public const short FlagRawOnly = 0x2;
+
+        /** Byte-sized field offsets flag. */
+        public const short FlagByteOffsets = 0x4;
+
+        /** Short-sized field offsets flag. */
+        public const short FlagShortOffsets = 0x8;
 
         /** Actual header layout */
         public readonly byte Header;        // Header code, always 103 (HdrFull)
@@ -50,7 +56,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         public readonly int SchemaOffset;   // Schema offset, or raw offset when RawOnly flag is set.
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="PortableObjectHeader"/> struct.
+        /// Initializes a new instance of the <see cref="PortableObjectHeader" /> struct.
         /// </summary>
         /// <param name="userType">User type flag.</param>
         /// <param name="typeId">Type ID.</param>
@@ -59,18 +65,23 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <param name="schemaId">Schema ID.</param>
         /// <param name="schemaOffset">Schema offset.</param>
         /// <param name="rawOnly">Raw flag.</param>
-        public PortableObjectHeader(bool userType, int typeId, int hashCode, int length, int schemaId, int schemaOffset, bool rawOnly)
+        /// <param name="flags">The flags.</param>
+        public PortableObjectHeader(bool userType, int typeId, int hashCode, int length, int schemaId, int schemaOffset, 
+            bool rawOnly, short flags)
         {
             Header = PortableUtils.HdrFull;
             Version = PortableUtils.ProtoVer;
 
             Debug.Assert(schemaOffset <= length);
             Debug.Assert(schemaOffset >= Size);
-            
-            Flags = (short) (userType ? FlagUserType : 0);
+
+            if (userType)
+                flags |= FlagUserType;
 
             if (rawOnly)
-                Flags = (short) (Flags | FlagRawOnly);
+                flags |= FlagRawOnly;
+
+            Flags = flags;
 
             TypeId = typeId;
             HashCode = hashCode;
@@ -134,49 +145,50 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             get
             {
-                // Odd amount of records in schema => raw offset is the very last 4 bytes in object.
-                return !IsRawOnly && (((Length - SchemaOffset) >> 2) & 0x1) != 0x0;
+                // Remainder => raw offset is the very last 4 bytes in object.
+                return !IsRawOnly && ((Length - SchemaOffset) % SchemaFieldSize) == 4;
             }
         }
 
         /// <summary>
-        /// Gets the schema field count.
+        /// Gets the size of the schema field offset (1, 2 or 4 bytes).
         /// </summary>
-        public int SchemaFieldCount
+        public int SchemaFieldOffsetSize
         {
             get
             {
-                if (IsRawOnly)
-                    return 0;
-
-                var schemaSize = Length - SchemaOffset;
+                if ((Flags & FlagByteOffsets) == FlagByteOffsets)
+                    return 1;
 
-                if (HasRawOffset)
-                    schemaSize -= 4;
+                if ((Flags & FlagShortOffsets) == FlagShortOffsets)
+                    return 2;
 
-                return schemaSize >> 3;  // 8 == PortableObjectSchemaField.Size
+                return 4;
             }
         }
 
         /// <summary>
-        /// Gets the schema end.
+        /// Gets the size of the schema field.
         /// </summary>
-        public int GetSchemaEnd(int position)
+        public int SchemaFieldSize
         {
-            var res = position + Length;
-
-            if (HasRawOffset)
-                res -= 4;
-
-            return res;
+            get { return SchemaFieldOffsetSize + 4; }
         }
 
         /// <summary>
-        /// Gets the schema start.
+        /// Gets the schema field count.
         /// </summary>
-        public int GetSchemaStart(int position)
+        public int SchemaFieldCount
         {
-            return IsRawOnly ? GetSchemaEnd(position) : position + SchemaOffset;
+            get
+            {
+                if (IsRawOnly)
+                    return 0;
+
+                var schemaSize = Length - SchemaOffset;
+
+                return schemaSize / SchemaFieldSize;
+            }
         }
 
         /// <summary>
@@ -214,10 +226,25 @@ namespace Apache.Ignite.Core.Impl.Portable
 
             stream.Seek(position + SchemaOffset, SeekOrigin.Begin);
 
-            var schema = new Dictionary<int, int>(schemaSize >> 3);
+            var schema = new Dictionary<int, int>(schemaSize);
+
+            var offsetSize = SchemaFieldOffsetSize;
 
-            for (var i = 0; i < schemaSize; i++)
-                schema.Add(stream.ReadInt(), stream.ReadInt());
+            if (offsetSize == 1)
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema.Add(stream.ReadInt(), stream.ReadByte());
+            }
+            else if (offsetSize == 2)
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema.Add(stream.ReadInt(), stream.ReadShort());
+            }
+            else
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema.Add(stream.ReadInt(), stream.ReadInt());
+            }
 
             return schema;
         }
@@ -239,7 +266,98 @@ namespace Apache.Ignite.Core.Impl.Portable
 
             stream.Seek(position + SchemaOffset, SeekOrigin.Begin);
 
-            return PortableObjectSchemaField.ReadArray(stream, schemaSize);
+            var schema = new PortableObjectSchemaField[schemaSize];
+
+            var offsetSize = SchemaFieldOffsetSize;
+
+            if (offsetSize == 1)
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema[i] = new PortableObjectSchemaField(stream.ReadInt(), stream.ReadByte());
+            }
+            else if (offsetSize == 2)
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema[i] = new PortableObjectSchemaField(stream.ReadInt(), stream.ReadShort());
+            }
+            else
+            {
+                for (var i = 0; i < schemaSize; i++)
+                    schema[i] = new PortableObjectSchemaField(stream.ReadInt(), stream.ReadInt());
+            }
+
+            return schema;
+        }
+
+        /// <summary>
+        /// Writes an array of fields to a stream.
+        /// </summary>
+        /// <param name="fields">Fields.</param>
+        /// <param name="stream">Stream.</param>
+        /// <param name="count">Field count to write.</param>
+        /// <param name="maxOffset">The maximum field offset to determine 
+        /// whether 1, 2 or 4 bytes are needed for offsets.</param>
+        /// <returns>
+        /// Flags according to offset sizes: <see cref="PortableObjectHeader.FlagByteOffsets"/>, 
+        /// <see cref="PortableObjectHeader.FlagShortOffsets"/>, or 0.
+        /// </returns>
+        public static unsafe short WriteSchema(PortableObjectSchemaField[] fields, IPortableStream stream, int count,
+            int maxOffset)
+        {
+            Debug.Assert(fields != null);
+            Debug.Assert(stream != null);
+            Debug.Assert(count > 0);
+
+            unchecked
+            {
+                if (maxOffset <= byte.MaxValue)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        var field = fields[i];
+
+                        stream.WriteInt(field.Id);
+                        stream.WriteByte((byte)field.Offset);
+                    }
+
+                    return FlagByteOffsets;
+                }
+
+                if (maxOffset <= ushort.MaxValue)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        var field = fields[i];
+
+                        stream.WriteInt(field.Id);
+
+                        stream.WriteShort((short)field.Offset);
+                    }
+
+                    return FlagShortOffsets;
+                }
+
+                if (BitConverter.IsLittleEndian)
+                {
+                    fixed (PortableObjectSchemaField* ptr = &fields[0])
+                    {
+                        stream.Write((byte*)ptr, count / PortableObjectSchemaField.Size);
+                    }
+                }
+                else
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        var field = fields[i];
+
+                        stream.WriteInt(field.Id);
+                        stream.WriteInt(field.Offset);
+                    }
+                }
+
+                return 0;
+            }
+
         }
 
         /// <summary>
@@ -284,6 +402,10 @@ namespace Apache.Ignite.Core.Impl.Portable
                 Debug.Assert(hdr.SchemaOffset <= hdr.Length);
                 Debug.Assert(hdr.SchemaOffset >= Size);
 
+                // Only one of the flags can be set
+                var f = hdr.Flags;
+                Debug.Assert((f & (FlagShortOffsets | FlagByteOffsets)) != (FlagShortOffsets | FlagByteOffsets));
+
                 return hdr;
             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchema.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchema.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchema.cs
index 7d3663c..51ae34e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchema.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchema.cs
@@ -20,7 +20,7 @@ namespace Apache.Ignite.Core.Impl.Portable
     using System.Collections.Generic;
 
     /// <summary>
-    /// Holds and manages portable object schema for a specific type.
+    /// Holds and manages portable object schemas for a specific type.
     /// </summary>
     internal class PortableObjectSchema
     {
@@ -44,7 +44,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// </summary>
         /// <param name="id">Schema id.</param>
         /// <returns>Schema or null.</returns>
-        public int[] GetSchema(int id)
+        public int[] Get(int id)
         {
             if (_schemaId1 == id)
                 return _schema1;
@@ -65,7 +65,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// </summary>
         /// <param name="id">Schema id.</param>
         /// <param name="schema">Schema.</param>
-        public void AddSchema(int id, int[] schema)
+        public void Add(int id, int[] schema)
         {
             lock (this)
             {

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchemaField.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchemaField.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchemaField.cs
index 48fd9c1..bc18191 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchemaField.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableObjectSchemaField.cs
@@ -17,15 +17,12 @@
 
 namespace Apache.Ignite.Core.Impl.Portable
 {
-    using System;
-    using System.Diagnostics;
     using System.Runtime.InteropServices;
-    using Apache.Ignite.Core.Impl.Portable.IO;
 
     /// <summary>
     /// Portable schema field DTO (as it is stored in a stream).
     /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
+    [StructLayout(LayoutKind.Sequential, Pack = 0)]
     internal struct PortableObjectSchemaField
     {
         /* Field ID */
@@ -35,7 +32,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         public readonly int Offset;
 
         /** Size, equals to sizeof(PortableObjectSchemaField) */
-        private const int Size = 8;
+        public const int Size = 8;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PortableObjectSchemaField"/> struct.
@@ -47,67 +44,5 @@ namespace Apache.Ignite.Core.Impl.Portable
             Id = id;
             Offset = offset;
         }
-
-        /// <summary>
-        /// Writes an array of fields to a stream.
-        /// </summary>
-        /// <param name="fields">Fields.</param>
-        /// <param name="stream">Stream.</param>
-        /// <param name="count">Field count to write.</param>
-        public static unsafe void WriteArray(PortableObjectSchemaField[] fields, IPortableStream stream, int count)
-        {
-            Debug.Assert(fields != null);
-            Debug.Assert(stream != null);
-            Debug.Assert(count > 0);
-
-            if (BitConverter.IsLittleEndian)
-            {
-                fixed (PortableObjectSchemaField* ptr = &fields[0])
-                {
-                    stream.Write((byte*) ptr, count * Size);
-                }
-            }
-            else
-            {
-                for (int i = 0; i < count; i++)
-                {
-                    var field = fields[i];
-
-                    stream.WriteInt(field.Id);
-                    stream.WriteInt(field.Offset);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Reads an array of fields from a stream.
-        /// </summary>
-        /// <param name="stream">Stream.</param>
-        /// <param name="count">Count.</param>
-        /// <returns></returns>
-        public static unsafe PortableObjectSchemaField[] ReadArray(IPortableStream stream, int count)
-        {
-            Debug.Assert(stream != null);
-            Debug.Assert(count > 0);
-
-            var res = new PortableObjectSchemaField[count];
-
-            if (BitConverter.IsLittleEndian)
-            {
-                fixed (PortableObjectSchemaField* ptr = &res[0])
-                {
-                    stream.Read((byte*) ptr, count * Size);
-                }
-            }
-            else
-            {
-                for (int i = 0; i < count; i++) 
-                {
-                    res[i] = new PortableObjectSchemaField(stream.ReadInt(), stream.ReadInt());
-                }
-            }
-
-            return res;
-        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
index 48ea799..2b7ddb8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableReaderImpl.cs
@@ -45,15 +45,9 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Handles. */
         private PortableReaderHandleDictionary _hnds;
 
-        /** Current type ID. */
-        private int _curTypeId;
-
         /** Current position. */
         private int _curPos;
 
-        /** Current raw data offset. */
-        private int _curRawOffset;
-
         /** Current raw flag. */
         private bool _curRaw;
 
@@ -66,14 +60,14 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Current type structure tracker. */
         private PortableStructureTracker _curStruct;
 
-        /** */
-        private int _curFooterStart;
+        /** Current schema. */
+        private int[] _curSchema;
 
-        /** */
-        private int _curFooterEnd;
+        /** Current schema with positions. */
+        private Dictionary<int, int> _curSchemaMap;
 
-        /** */
-        private int[] _curSchema;
+        /** Current header. */
+        private PortableObjectHeader _curHdr;
 
         /// <summary>
         /// Constructor.
@@ -432,9 +426,7 @@ namespace Apache.Ignite.Core.Impl.Portable
             if (_curRaw)
                 throw new PortableException("Cannot read named fields after raw data is read.");
 
-            int fieldId = _curStruct.GetFieldId(fieldName);
-
-            if (SeekField(fieldId))
+            if (SeekField(fieldName))
                 return Deserialize<T>();
 
             return default(T);
@@ -669,31 +661,26 @@ namespace Apache.Ignite.Core.Impl.Portable
                                                     desc.TypeId + ", typeName=" + desc.TypeName + ']');
 
                     // Preserve old frame.
-                    int oldTypeId = _curTypeId;
+                    var oldHdr = _curHdr;
                     int oldPos = _curPos;
-                    int oldRawOffset = _curRawOffset;
                     var oldStruct = _curStruct;
                     bool oldRaw = _curRaw;
-                    var oldFooterStart = _curFooterStart;
-                    var oldFooterEnd = _curFooterEnd;
                     var oldSchema = _curSchema;
+                    var oldSchemaMap = _curSchemaMap;
 
                     // Set new frame.
-                    _curTypeId = hdr.TypeId;
+                    _curHdr = hdr;
                     _curPos = pos;
-                    _curFooterEnd = hdr.GetSchemaEnd(pos);
-                    _curFooterStart = hdr.GetSchemaStart(pos);
                     
-                    _curSchema = desc.Schema.GetSchema(hdr.SchemaId);
+                    _curSchema = desc.Schema.Get(hdr.SchemaId);
 
                     if (_curSchema == null)
                     {
                         _curSchema = ReadSchema();
 
-                        desc.Schema.AddSchema(hdr.SchemaId, _curSchema);
+                        desc.Schema.Add(hdr.SchemaId, _curSchema);
                     }
 
-                    _curRawOffset = hdr.GetRawOffset(Stream, pos);
                     _curStruct = new PortableStructureTracker(desc, desc.ReaderTypeStructure);
                     _curRaw = false;
 
@@ -727,14 +714,12 @@ namespace Apache.Ignite.Core.Impl.Portable
                     _curStruct.UpdateReaderStructure();
 
                     // Restore old frame.
-                    _curTypeId = oldTypeId;
+                    _curHdr = oldHdr;
                     _curPos = oldPos;
-                    _curRawOffset = oldRawOffset;
                     _curStruct = oldStruct;
                     _curRaw = oldRaw;
-                    _curFooterStart = oldFooterStart;
-                    _curFooterEnd = oldFooterEnd;
                     _curSchema = oldSchema;
+                    _curSchemaMap = oldSchemaMap;
 
                     // Process wrappers. We could introduce a common interface, but for only 2 if-else is faster.
                     var wrappedSerializable = obj as SerializableObjectHolder;
@@ -762,21 +747,22 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// </summary>
         private int[] ReadSchema()
         {
-            Stream.Seek(_curFooterStart, SeekOrigin.Begin);
-            
-            var count = (_curFooterEnd - _curFooterStart) >> 3;
-            
+            Stream.Seek(_curPos + _curHdr.SchemaOffset, SeekOrigin.Begin);
+
+            var count = _curHdr.SchemaFieldCount;
+
+            var offsetSize = _curHdr.SchemaFieldOffsetSize;
+
             var res = new int[count];
 
             for (int i = 0; i < count; i++)
             {
                 res[i] = Stream.ReadInt();
-                Stream.Seek(4, SeekOrigin.Current);
+                Stream.Seek(offsetSize, SeekOrigin.Current);
             }
 
             return res;
         }
-
         /// <summary>
         /// Reads the handle object.
         /// </summary>
@@ -846,38 +832,11 @@ namespace Apache.Ignite.Core.Impl.Portable
             {
                 _curRaw = true;
 
-                Stream.Seek(_curPos + _curRawOffset, SeekOrigin.Begin);
+                Stream.Seek(_curPos + _curHdr.GetRawOffset(Stream, _curPos), SeekOrigin.Begin);
             }
         }
 
         /// <summary>
-        /// Seek field with the given ID in the current object.
-        /// </summary>
-        /// <param name="fieldId">Field ID.</param>
-        /// <returns>True in case the field was found and position adjusted, false otherwise.</returns>
-        private bool SeekField(int fieldId)
-        {
-            Stream.Seek(_curFooterStart, SeekOrigin.Begin);
-
-            while (Stream.Position < _curFooterEnd)
-            {
-                var id = Stream.ReadInt();
-
-                if (id == fieldId)
-                {
-                    var fieldOffset = Stream.ReadInt();
-
-                    Stream.Seek(_curPos + fieldOffset, SeekOrigin.Begin);
-                    return true;
-                }
-
-                Stream.Seek(4, SeekOrigin.Current);
-            }
-
-            return false;
-        }
-
-        /// <summary>
         /// Determines whether header at current position is HDR_NULL.
         /// </summary>
         private bool IsNotNullHeader(byte expHdr)
@@ -899,23 +858,43 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// </summary>
         private bool SeekField(string fieldName, byte expHdr)
         {
+            if (!SeekField(fieldName)) 
+                return false;
+
+            // Expected read order, no need to seek.
+            return IsNotNullHeader(expHdr);
+        }
+
+        /// <summary>
+        /// Seeks the field by name.
+        /// </summary>
+        private bool SeekField(string fieldName)
+        {
             if (_curRaw)
                 throw new PortableException("Cannot read named fields after raw data is read.");
 
+            if (_curHdr.IsRawOnly)
+                return false;
+
             var actionId = _curStruct.CurStructAction;
 
             var fieldId = _curStruct.GetFieldId(fieldName);
 
             if (_curSchema == null || actionId >= _curSchema.Length || fieldId != _curSchema[actionId])
             {
-                _curSchema = null;   // read order is different, ignore schema for future reads
+                _curSchema = null; // read order is different, ignore schema for future reads
+
+                _curSchemaMap = _curSchemaMap ?? _curHdr.ReadSchemaAsDictionary(Stream, _curPos);
+
+                int pos;
 
-                if (!SeekField(fieldId))
+                if (!_curSchemaMap.TryGetValue(fieldId, out pos))
                     return false;
+
+                Stream.Seek(pos, SeekOrigin.Begin);
             }
 
-            // Expected read order, no need to seek.
-            return IsNotNullHeader(expHdr);
+            return true;
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
index a0657b2..79c4858 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableUtils.cs
@@ -1804,7 +1804,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <summary>
         /// Struct with .Net-style Guid memory layout.
         /// </summary>
-        [StructLayout(LayoutKind.Sequential)]
+        [StructLayout(LayoutKind.Sequential, Pack = 0)]
         private struct GuidAccessor
         {
             public readonly ulong ABC;
@@ -1828,7 +1828,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         /// <summary>
         /// Struct with Java-style Guid memory layout.
         /// </summary>
-        [StructLayout(LayoutKind.Sequential)]
+        [StructLayout(LayoutKind.Sequential, Pack = 0)]
         private struct JavaGuid
         {
             public readonly ulong CBA;

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
index e17449d..66caca3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortableWriterImpl.cs
@@ -73,7 +73,6 @@ namespace Apache.Ignite.Core.Impl.Portable
         /** Current schema. */
         private ResizeableArray<PortableObjectSchemaField> _curSchema;
 
-
         /// <summary>
         /// Gets the marshaller.
         /// </summary>
@@ -1092,9 +1091,11 @@ namespace Apache.Ignite.Core.Impl.Portable
                 // Write schema
                 var hasSchema = _curSchema != null;
                 var schemaOffset = hasSchema ? _stream.Position - pos : PortableObjectHeader.Size;
+                short flags = 0;
 
                 if (hasSchema)
-                    PortableObjectSchemaField.WriteArray(_curSchema.Array, _stream, _curSchema.Count);
+                    flags = PortableObjectHeader.WriteSchema(_curSchema.Array, _stream, _curSchema.Count,
+                        _curSchema.Array[_curSchema.Count - 1].Offset);
 
                 // Calculate and write header.
                 if (hasSchema && _curRawPos > 0)
@@ -1103,7 +1104,7 @@ namespace Apache.Ignite.Core.Impl.Portable
                 var len = _stream.Position - pos;
 
                 var header = new PortableObjectHeader(desc.UserType, desc.TypeId, obj.GetHashCode(), len,
-                    PU.GetSchemaId(_curSchema), schemaOffset, !hasSchema);
+                    PU.GetSchemaId(_curSchema), schemaOffset, !hasSchema, flags);
 
                 PortableObjectHeader.Write(header, _stream, pos);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
index f48f120..e72ffac 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Portable/PortablesImpl.cs
@@ -166,7 +166,7 @@ namespace Apache.Ignite.Core.Impl.Portable
         {
             var len = PortableObjectHeader.Size;
 
-            var hdr = new PortableObjectHeader(desc.UserType, desc.TypeId, 0, len, 0, len, true);
+            var hdr = new PortableObjectHeader(desc.UserType, desc.TypeId, 0, len, 0, len, true, 0);
 
             var stream = new PortableHeapStream(len);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackHandlers.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackHandlers.cs
index 07cf309..8147e9d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbackHandlers.cs
@@ -22,7 +22,7 @@ namespace Apache.Ignite.Core.Impl.Unmanaged
     /// <summary>
     /// Unmanaged callback handler function pointers.
     /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
+    [StructLayout(LayoutKind.Sequential, Pack = 0)]
     internal unsafe struct UnmanagedCallbackHandlers
     {
         internal void* target;


[2/2] ignite git commit: IGNITE-1418: Implemented compact field offsets.

Posted by vo...@apache.org.
IGNITE-1418: Implemented compact field offsets.


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

Branch: refs/heads/ignite-1282
Commit: 845c4f2722e69aa1f7ccd8ff619c52a013eb775a
Parents: fd640d7
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Tue Nov 3 13:16:10 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Tue Nov 3 13:16:10 2015 +0300

----------------------------------------------------------------------
 .gitignore                                      |   7 +
 .../portable/PortableClassDescriptor.java       |  33 ++-
 .../internal/portable/PortableFieldImpl.java    |  10 +-
 .../internal/portable/PortableObjectEx.java     |   2 +-
 .../internal/portable/PortableObjectImpl.java   |  46 ++-
 .../portable/PortableObjectOffheapImpl.java     |  89 +++++-
 .../internal/portable/PortableReaderExImpl.java |  41 +--
 .../internal/portable/PortableSchema.java       | 133 ++++-----
 .../ignite/internal/portable/PortableUtils.java |  46 ++-
 .../internal/portable/PortableWriterExImpl.java |  76 ++++-
 .../portable/builder/PortableBuilderImpl.java   | 283 ++++++++++---------
 .../src/portable_reader_writer_test.cpp         | 251 +++++++++++++---
 .../ignite/impl/interop/interop_input_stream.h  |  16 ++
 .../ignite/impl/interop/interop_output_stream.h |   8 +
 .../ignite/impl/portable/portable_common.h      |   6 +
 .../ignite/impl/portable/portable_reader_impl.h |  29 +-
 .../ignite/impl/portable/portable_schema.h      |  26 +-
 .../src/impl/interop/interop_input_stream.cpp   |  20 ++
 .../src/impl/interop/interop_output_stream.cpp  |   7 +
 .../src/impl/portable/portable_reader_impl.cpp  |  45 ++-
 .../core/src/impl/portable/portable_schema.cpp  |  53 +++-
 .../src/impl/portable/portable_writer_impl.cpp  |  21 +-
 .../Portable/PortableSelfTest.cs                |  32 +++
 .../Impl/Common/ResizeableArray.cs              |  14 +-
 .../Apache.Ignite.Core/Impl/ExceptionUtils.cs   |   2 -
 .../Impl/Portable/PortableBuilderImpl.cs        |   8 +-
 .../Impl/Portable/PortableObjectHeader.cs       | 196 ++++++++++---
 .../Impl/Portable/PortableObjectSchema.cs       |   6 +-
 .../Impl/Portable/PortableObjectSchemaField.cs  |  69 +----
 .../Impl/Portable/PortableReaderImpl.cs         | 113 +++-----
 .../Impl/Portable/PortableUtils.cs              |   4 +-
 .../Impl/Portable/PortableWriterImpl.cs         |   7 +-
 .../Impl/Portable/PortablesImpl.cs              |   2 +-
 .../Impl/Unmanaged/UnmanagedCallbackHandlers.cs |   2 +-
 34 files changed, 1145 insertions(+), 558 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 3da8e4d..22e3cc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,10 @@ target
 pom-installed.xml
 git-patch-prop-local.sh
 /slurp.sh
+*.vcxproj.user
+Apache.Ignite.sdf
+ignite.sdf
+ignite.opensdf
+**/cpp/**/vs/x64/
+**/cpp/**/vs/Win32/
+**/dotnet/**/obj/

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/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 9f7f0c6..aa72017 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
@@ -524,12 +524,17 @@ public class PortableClassDescriptor {
 
             case PORTABLE:
                 if (writeHeader(obj, writer)) {
-                    if (serializer != null)
-                        serializer.writePortable(obj, writer);
-                    else
-                        ((PortableMarshalAware)obj).writePortable(writer);
+                    try {
+                        if (serializer != null)
+                            serializer.writePortable(obj, writer);
+                        else
+                            ((PortableMarshalAware) obj).writePortable(writer);
 
-                    writer.postWrite(userType);
+                        writer.postWrite(userType);
+                    }
+                    finally {
+                        writer.popSchema();
+                    }
 
                     if (obj.getClass() != PortableMetaDataImpl.class
                         && ctx.isMetaDataChanged(typeId, writer.metaDataHashSum())) {
@@ -552,22 +557,30 @@ public class PortableClassDescriptor {
 
                     try {
                         ((Externalizable)obj).writeExternal(writer);
+
+                        writer.postWrite(userType);
                     }
                     catch (IOException e) {
                         throw new PortableException("Failed to write Externalizable object: " + obj, e);
                     }
-
-                    writer.postWrite(userType);
+                    finally {
+                        writer.popSchema();
+                    }
                 }
 
                 break;
 
             case OBJECT:
                 if (writeHeader(obj, writer)) {
-                    for (FieldInfo info : fields)
-                        info.write(obj, writer);
+                    try {
+                        for (FieldInfo info : fields)
+                            info.write(obj, writer);
 
-                    writer.postWrite(userType);
+                        writer.postWrite(userType);
+                    }
+                    finally {
+                        writer.popSchema();
+                    }
                 }
 
                 break;

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableFieldImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableFieldImpl.java
index 5780b76..12be55c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableFieldImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableFieldImpl.java
@@ -45,7 +45,7 @@ public class PortableFieldImpl implements PortableField {
     @Override public boolean exists(PortableObject obj) {
         PortableObjectEx obj0 = (PortableObjectEx)obj;
 
-        return fieldOffset(obj0) != 0;
+        return fieldOrder(obj0) != 0;
     }
 
     /** {@inheritDoc} */
@@ -53,9 +53,9 @@ public class PortableFieldImpl implements PortableField {
     @Override public <T> T value(PortableObject obj) {
         PortableObjectEx obj0 = (PortableObjectEx)obj;
 
-        int offset = fieldOffset(obj0);
+        int order = fieldOrder(obj0);
 
-        return offset != 0 ? (T)obj0.fieldByOffset(offset) : null;
+        return order != 0 ? (T)obj0.fieldByOrder(order) : null;
     }
 
     /**
@@ -64,7 +64,7 @@ public class PortableFieldImpl implements PortableField {
      * @param obj Object.
      * @return Field offset.
      */
-    private int fieldOffset(PortableObjectEx obj) {
+    private int fieldOrder(PortableObjectEx obj) {
         int schemaId = obj.schemaId();
 
         PortableSchema schema = schemas.schema(schemaId);
@@ -77,6 +77,6 @@ public class PortableFieldImpl implements PortableField {
 
         assert schema != null;
 
-        return schema.offset(fieldId);
+        return schema.order(fieldId);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectEx.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectEx.java
index 42c973b..d6d7f50 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectEx.java
@@ -72,7 +72,7 @@ public abstract class PortableObjectEx implements PortableObject {
      * @param fieldOffset Field offset.
      * @return Field value.
      */
-    @Nullable protected abstract <F> F fieldByOffset(int fieldOffset);
+    @Nullable protected abstract <F> F fieldByOrder(int fieldOffset);
 
     /**
      * @param ctx Reader context.

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectImpl.java
index a1272d0..c7e01d7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectImpl.java
@@ -256,11 +256,25 @@ public final class PortableObjectImpl extends PortableObjectEx implements Extern
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
-    @Nullable @Override protected <F> F fieldByOffset(int fieldOffset) {
+    @Nullable @Override protected <F> F fieldByOrder(int order) {
         Object val;
 
+        // Calculate field position.
         int schemaOffset = PortablePrimitives.readInt(arr, start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
-        int fieldPos = PortablePrimitives.readInt(arr, start + schemaOffset + fieldOffset);
+
+        short flags = PortablePrimitives.readShort(arr, start + GridPortableMarshaller.FLAGS_POS);
+        int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
+
+        int fieldOffsetPos = start + schemaOffset + order * (4 + fieldOffsetSize) + 4;
+
+        int fieldPos;
+
+        if (fieldOffsetSize == PortableUtils.OFFSET_1)
+            fieldPos = start + (int)PortablePrimitives.readByte(arr, fieldOffsetPos) & 0xFF;
+        else if (fieldOffsetSize == PortableUtils.OFFSET_2)
+            fieldPos = start + (int)PortablePrimitives.readShort(arr, fieldOffsetPos) & 0xFFFF;
+        else
+            fieldPos = start + PortablePrimitives.readInt(arr, fieldOffsetPos);
 
         // Read header and try performing fast lookup for well-known types (the most common types go first).
         byte hdr = PortablePrimitives.readByte(arr, fieldPos);
@@ -306,36 +320,10 @@ public final class PortableObjectImpl extends PortableObjectEx implements Extern
 
                 break;
 
-//            case DECIMAL:
-//                val = doReadDecimal();
-//
-//                break;
-//
-//            case STRING:
-//                val = doReadString();
-//
-//                break;
-//
-//            case UUID:
-//                val = doReadUuid();
-//
-//                break;
-//
-//            case DATE:
-//                val = doReadDate();
-//
-//                break;
-//
-//            case TIMESTAMP:
-//                val = doReadTimestamp();
-//
-//                break;
-
             default: {
-                // TODO: Pass absolute offset, not relative.
                 PortableReaderExImpl reader = new PortableReaderExImpl(ctx, arr, start, null);
 
-                val = reader.unmarshalFieldByOffset(fieldOffset);
+                val = reader.unmarshalFieldByAbsolutePosition(fieldPos);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectOffheapImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectOffheapImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectOffheapImpl.java
index f023f2e..7ba5553 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectOffheapImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectOffheapImpl.java
@@ -37,6 +37,15 @@ import org.apache.ignite.portable.PortableObject;
 import org.jetbrains.annotations.Nullable;
 import sun.misc.Unsafe;
 
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT;
+
 /**
  *  Portable object implementation over offheap memory
  */
@@ -179,13 +188,81 @@ public class PortableObjectOffheapImpl extends PortableObjectEx implements Exter
 
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
-    @Nullable @Override protected <F> F fieldByOffset(int fieldOffset) {
-        PortableReaderExImpl reader = new PortableReaderExImpl(ctx,
-            new PortableOffheapInputStream(ptr, size, false),
-            start,
-            null);
+    @Nullable @Override protected <F> F fieldByOrder(int order) {
+        Object val;
+
+        // Calculate field position.
+        int schemaOffset = PortablePrimitives.readInt(ptr, start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
+
+        short flags = PortablePrimitives.readShort(ptr, start + GridPortableMarshaller.FLAGS_POS);
+        int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
+
+        int fieldOffsetPos = start + schemaOffset + order * (4 + fieldOffsetSize) + 4;
+
+        int fieldPos;
+
+        if (fieldOffsetSize == PortableUtils.OFFSET_1)
+            fieldPos = start + (int)PortablePrimitives.readByte(ptr, fieldOffsetPos) & 0xFF;
+        else if (fieldOffsetSize == PortableUtils.OFFSET_2)
+            fieldPos = start + (int)PortablePrimitives.readShort(ptr, fieldOffsetPos) & 0xFFFF;
+        else
+            fieldPos = start + PortablePrimitives.readInt(ptr, fieldOffsetPos);
+
+        // Read header and try performing fast lookup for well-known types (the most common types go first).
+        byte hdr = PortablePrimitives.readByte(ptr, fieldPos);
+
+        switch (hdr) {
+            case INT:
+                val = PortablePrimitives.readInt(ptr, fieldPos + 1);
+
+                break;
+
+            case LONG:
+                val = PortablePrimitives.readLong(ptr, fieldPos + 1);
+
+                break;
+
+            case BOOLEAN:
+                val = PortablePrimitives.readBoolean(ptr, fieldPos + 1);
+
+                break;
+
+            case SHORT:
+                val = PortablePrimitives.readShort(ptr, fieldPos + 1);
+
+                break;
+
+            case BYTE:
+                val = PortablePrimitives.readByte(ptr, fieldPos + 1);
+
+                break;
+
+            case CHAR:
+                val = PortablePrimitives.readChar(ptr, fieldPos + 1);
+
+                break;
+
+            case FLOAT:
+                val = PortablePrimitives.readFloat(ptr, fieldPos + 1);
+
+                break;
+
+            case DOUBLE:
+                val = PortablePrimitives.readDouble(ptr, fieldPos + 1);
+
+                break;
+
+            default: {
+                PortableReaderExImpl reader = new PortableReaderExImpl(ctx,
+                    new PortableOffheapInputStream(ptr, size, false),
+                    start,
+                    null);
+
+                val = reader.unmarshalFieldByAbsolutePosition(fieldPos);
+            }
+        }
 
-        return (F)reader.unmarshalFieldByOffset(fieldOffset);
+        return (F)val;
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderExImpl.java
index aa1519d..061a9fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderExImpl.java
@@ -163,6 +163,9 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
     /** Schema Id. */
     private int schemaId;
 
+    /** Offset size in bytes. */
+    private int offsetSize;
+
     /** Object schema. */
     private PortableSchema schema;
 
@@ -221,18 +224,20 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
 
         PortableUtils.checkProtocolVersion(in.readByte());
 
-        in.position(in.position() + 2); // Skip flags.
+        short flags = in.readShort();
+
+        offsetSize = PortableUtils.fieldOffsetSize(flags);
 
         typeId = in.readIntPositioned(start + GridPortableMarshaller.TYPE_ID_POS);
 
-        IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(in, start);
+        IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(in, start, offsetSize);
 
         footerStart = footer.get1();
         footerLen = footer.get2() - footerStart;
 
         schemaId = in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_ID_POS);
 
-        rawOff = PortableUtils.rawOffsetAbsolute(in, start);
+        rawOff = PortableUtils.rawOffsetAbsolute(in, start, offsetSize);
 
         if (typeId == UNREGISTERED_TYPE_ID) {
             // Skip to the class name position.
@@ -307,16 +312,16 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
     }
 
     /**
-     * @param fieldOffset Field offset.
-     * @return Unmarshalled value.
+     * Unmarshal field by absolute position.
+     *
+     * @param pos Absolute position.
+     * @return Field value.
      * @throws PortableException In case of error.
      */
-    @Nullable Object unmarshalFieldByOffset(int fieldOffset) throws PortableException {
-        assert fieldOffset != 0;
-
+    @Nullable Object unmarshalFieldByAbsolutePosition(int pos) throws PortableException {
         parseHeaderIfNeeded();
 
-        in.position(start + in.readIntPositioned(footerStart + fieldOffset));
+        in.position(pos);
 
         return unmarshal();
     }
@@ -2567,12 +2572,14 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
         int searchPos = footerStart;
         int searchEnd = searchPos + footerLen;
 
+        int idx = 0;
+
         while (searchPos < searchEnd) {
             int fieldId = in.readIntPositioned(searchPos);
 
-            fields.put(fieldId, searchPos + 4 - footerStart);
+            fields.put(fieldId, idx++);
 
-            searchPos += 8;
+            searchPos += 4 + offsetSize;
         }
 
         return new PortableSchema(fields);
@@ -2599,14 +2606,14 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
                 int id0 = in.readIntPositioned(searchPos);
 
                 if (id0 == id) {
-                    int pos = start + in.readIntPositioned(searchPos + 4);
+                    int pos = start + PortableUtils.fieldOffsetRelative(in, searchPos + 4, offsetSize);
 
                     in.position(pos);
 
                     return pos;
                 }
 
-                searchPos += 8;
+                searchPos += 4 + offsetSize;
             }
         }
         else {
@@ -2624,10 +2631,12 @@ public class PortableReaderExImpl implements PortableReader, PortableRawReaderEx
                 schema = schema0;
             }
 
-            int fieldOffsetPos = schema.offset(id);
+            int order = schema.order(id);
+
+            if (order != 0) {
+                int offsetPos = footerStart + order * (4 + offsetSize) + 4;
 
-            if (fieldOffsetPos != 0) {
-                int pos = start + in.readIntPositioned(footerStart + fieldOffsetPos);
+                int pos = start + PortableUtils.fieldOffsetRelative(in, offsetPos, offsetSize);
 
                 in.position(pos);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/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 09bfe35..03be319 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
@@ -36,52 +36,28 @@ public class PortableSchema {
     private final HashMap<Integer, Integer> map;
 
     /** ID 1. */
-    private final int id1;
-
-    /** Offset 1. */
-    private final int offset1;
+    private final int id0;
 
     /** ID 2. */
-    private final int id2;
-
-    /** Offset 2. */
-    private final int offset2;
+    private final int id1;
 
     /** ID 3. */
-    private final int id3;
-
-    /** Offset 3. */
-    private final int offset3;
+    private final int id2;
 
     /** ID 4. */
-    private final int id4;
-
-    /** Offset 4. */
-    private final int offset4;
+    private final int id3;
 
     /** ID 1. */
-    private final int id5;
-
-    /** Offset 1. */
-    private final int offset5;
+    private final int id4;
 
     /** ID 2. */
-    private final int id6;
-
-    /** Offset 2. */
-    private final int offset6;
+    private final int id5;
 
     /** ID 3. */
-    private final int id7;
-
-    /** Offset 3. */
-    private final int offset7;
+    private final int id6;
 
     /** ID 4. */
-    private final int id8;
-
-    /** Offset 4. */
-    private final int offset8;
+    private final int id7;
 
     /**
      * Constructor.
@@ -97,120 +73,111 @@ public class PortableSchema {
             Map.Entry<Integer, Integer> entry = iter.hasNext() ? iter.next() : null;
 
             if (entry != null) {
+                id0 = entry.getKey();
+
+                assert entry.getValue() == 0;
+            }
+            else
+                id0 = 0;
+
+            if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id1 = entry.getKey();
-                offset1 = entry.getValue();
+
+                assert entry.getValue() == 1;
             }
-            else{
+            else
                 id1 = 0;
-                offset1 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id2 = entry.getKey();
-                offset2 = entry.getValue();
+
+                assert entry.getValue() == 2;
             }
-            else{
+            else
                 id2 = 0;
-                offset2 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id3 = entry.getKey();
-                offset3 = entry.getValue();
+
+                assert entry.getValue() == 3;
             }
-            else{
+            else
                 id3 = 0;
-                offset3 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id4 = entry.getKey();
-                offset4 = entry.getValue();
+
+                assert entry.getValue() == 4;
             }
-            else{
+            else
                 id4 = 0;
-                offset4 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id5 = entry.getKey();
-                offset5 = entry.getValue();
+
+                assert entry.getValue() == 5;
             }
-            else{
+            else
                 id5 = 0;
-                offset5 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id6 = entry.getKey();
-                offset6 = entry.getValue();
+
+                assert entry.getValue() == 6;
             }
-            else{
+            else
                 id6 = 0;
-                offset6 = 0;
-            }
 
             if ((entry = iter.hasNext() ? iter.next() : null) != null) {
                 id7 = entry.getKey();
-                offset7 = entry.getValue();
-            }
-            else{
-                id7 = 0;
-                offset7 = 0;
-            }
 
-            if ((entry = iter.hasNext() ? iter.next() : null) != null) {
-                id8 = entry.getKey();
-                offset8 = entry.getValue();
-            }
-            else{
-                id8 = 0;
-                offset8 = 0;
+                assert entry.getValue() == 7;
             }
+            else
+                id7 = 0;
 
             map = null;
         }
         else {
             inline = false;
 
-            id1 = id2 = id3 = id4 = id5 = id6 = id7 = id8 = 0;
-            offset1 = offset2 = offset3 = offset4 = offset5 = offset6 = offset7 = offset8 = 0;
+            id0 = id1 = id2 = id3 = id4 = id5 = id6 = id7 = 0;
 
             map = new HashMap<>(vals);
         }
     }
 
     /**
-     * Get offset for the given field ID.
+     * Get field position in footer by schema ID.
      *
      * @param id Field ID.
      * @return Offset or {@code 0} if there is no such field.
      */
-    public int offset(int id) {
+    public int order(int id) {
         if (inline) {
+            if (id == id0)
+                return 0;
+
             if (id == id1)
-                return offset1;
+                return 1;
 
             if (id == id2)
-                return offset2;
+                return 2;
 
             if (id == id3)
-                return offset3;
+                return 3;
 
             if (id == id4)
-                return offset4;
+                return 4;
 
             if (id == id5)
-                return offset5;
+                return 5;
 
             if (id == id6)
-                return offset6;
+                return 6;
 
             if (id == id7)
-                return offset7;
-
-            if (id == id8)
-                return offset8;
+                return 7;
 
             return 0;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/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 f57a29b..4e3538c 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
@@ -619,14 +619,16 @@ public class PortableUtils {
      *
      * @param in Input stream.
      * @param start Start position.
+     * @param fieldOffsetSize Field offset size.
      * @return Footer.
      */
-    public static IgniteBiTuple<Integer, Integer> footerAbsolute(PortablePositionReadable in, int start) {
+    public static IgniteBiTuple<Integer, Integer> footerAbsolute(PortablePositionReadable in, int start,
+        int fieldOffsetSize) {
         int footerStart = footerStartRelative(in, start);
         int footerEnd = length(in, start);
 
         // Take in count possible raw offset.
-        if ((((footerEnd - footerStart) >> 2) & 0x1) == 0x1)
+        if ((footerEnd - footerStart) % (4 + fieldOffsetSize) != 0)
             footerEnd -= 4;
 
         return F.t(start + footerStart, start + footerEnd);
@@ -637,9 +639,10 @@ public class PortableUtils {
      *
      * @param in Input stream.
      * @param start Object start position inside the stream.
+     * @param fieldOffsetSize Field offset size.
      * @return Raw offset.
      */
-    public static int rawOffsetAbsolute(PortablePositionReadable in, int start) {
+    public static int rawOffsetAbsolute(PortablePositionReadable in, int start, int fieldOffsetSize) {
         int len = length(in, start);
 
         short flags = in.readShortPositioned(start + GridPortableMarshaller.FLAGS_POS);
@@ -651,7 +654,7 @@ public class PortableUtils {
             // Schema exists.
             int schemaOff = in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
 
-            if ((((len - schemaOff) >> 2) & 0x1) == 0x0)
+            if (((len - schemaOff) % (4 + fieldOffsetSize)) == 0x0)
                 // Even amount of records in schema => no raw offset.
                 return start + schemaOff;
             else
@@ -659,4 +662,39 @@ public class PortableUtils {
                 return start + in.readIntPositioned(start + len - 4);
         }
     }
+
+    /**
+     * Get offset size for the given flags.
+     * @param flags Flags.
+     * @return Offset size.
+     */
+    public static int fieldOffsetSize(short flags) {
+        if ((flags & FLAG_OFFSET_ONE_BYTE) == FLAG_OFFSET_ONE_BYTE)
+            return OFFSET_1;
+        else if ((flags & FLAG_OFFSET_TWO_BYTES) == FLAG_OFFSET_TWO_BYTES)
+            return OFFSET_2;
+        else
+            return OFFSET_4;
+    }
+
+    /**
+     * Get relative field offset.
+     *
+     * @param stream Stream.
+     * @param pos Position.
+     * @param fieldOffsetSize Field offset size.
+     * @return Relative field offset.
+     */
+    public static int fieldOffsetRelative(PortablePositionReadable stream, int pos, int fieldOffsetSize) {
+        int res;
+
+        if (fieldOffsetSize == PortableUtils.OFFSET_1)
+            res = (int)stream.readBytePositioned(pos) & 0xFF;
+        else if (fieldOffsetSize == PortableUtils.OFFSET_2)
+            res = (int)stream.readShortPositioned(pos) & 0xFFFF;
+        else
+            res = stream.readIntPositioned(pos);
+
+        return res;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableWriterExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableWriterExImpl.java
index 227087b..ff85ecd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableWriterExImpl.java
@@ -99,6 +99,12 @@ public class PortableWriterExImpl implements PortableWriter, PortableRawWriterEx
     /** FNV1 hash prime. */
     private static final int FNV1_PRIME = 0x01000193;
 
+    /** 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<>();
 
@@ -342,11 +348,22 @@ public class PortableWriterExImpl implements PortableWriter, PortableRawWriterEx
             out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start);
 
             // Write the schema.
-            schema.writeAndPop(this, fieldCnt);
+            int offsetByteCnt = schema.write(this, fieldCnt);
 
             // Write raw offset if needed.
             if (rawOffPos != 0)
                 out.writeInt(rawOffPos - start);
+
+            if (offsetByteCnt == PortableUtils.OFFSET_1) {
+                int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_ONE_BYTE;
+
+                out.writeShort(start + FLAGS_POS, (short)flags);
+            }
+            else if (offsetByteCnt == PortableUtils.OFFSET_2) {
+                int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_TWO_BYTES;
+
+                out.writeShort(start + FLAGS_POS, (short)flags);
+            }
         }
         else {
             // Write raw-only flag is needed.
@@ -363,6 +380,17 @@ public class PortableWriterExImpl implements PortableWriter, PortableRawWriterEx
     }
 
     /**
+     * Pop schema.
+     */
+    public void popSchema() {
+        if (schema != null) {
+            assert fieldCnt > 0;
+
+            schema.pop(fieldCnt);
+        }
+    }
+
+    /**
      * @param val Byte array.
      */
     public void write(byte[] val) {
@@ -1833,19 +1861,51 @@ public class PortableWriterExImpl implements PortableWriter, PortableRawWriterEx
          * Write collected frames and pop them.
          *
          * @param writer Writer.
-         * @param cnt Count.
+         * @param fieldCnt Count.
+         * @return Amount of bytes dedicated to
          */
-        public void writeAndPop(PortableWriterExImpl writer, int cnt) {
-            int startIdx = idx - cnt * 2;
+        public int write(PortableWriterExImpl writer, int fieldCnt) {
+            int startIdx = idx - fieldCnt * 2;
 
             assert startIdx >= 0;
 
-            for (int idx0 = startIdx; idx0 < idx;) {
-                writer.writeInt(data[idx0++]);
-                writer.writeInt(data[idx0++]);
+            int lastOffset = data[idx - 1];
+
+            int res;
+
+            if (lastOffset < MAX_OFFSET_1) {
+                for (int idx0 = startIdx; idx0 < idx; ) {
+                    writer.writeInt(data[idx0++]);
+                    writer.writeByte((byte) data[idx0++]);
+                }
+
+                res = PortableUtils.OFFSET_1;
             }
+            else if (lastOffset < MAX_OFFSET_2) {
+                for (int idx0 = startIdx; idx0 < idx; ) {
+                    writer.writeInt(data[idx0++]);
+                    writer.writeShort((short)data[idx0++]);
+                }
+
+                res = PortableUtils.OFFSET_2;
+            }
+            else {
+                for (int idx0 = startIdx; idx0 < idx; ) {
+                    writer.writeInt(data[idx0++]);
+                    writer.writeInt(data[idx0++]);
+                }
 
-            idx = startIdx;
+                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)

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderImpl.java
index 34e1d6d..608425d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderImpl.java
@@ -41,6 +41,7 @@ import java.util.Map;
 import java.util.Set;
 
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.DFLT_HDR_LEN;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.HASH_CODE_POS;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.PROTO_VER_POS;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.TYPE_ID_POS;
@@ -77,12 +78,13 @@ public class PortableBuilderImpl implements PortableBuilder {
     /** Position of object in source array, or -1 if object is not created from PortableObject. */
     private final int start;
 
+    /** Flags. */
+    private final short flags;
+
     /** Total header length */
     private final int hdrLen;
 
-    /**
-     * Context of PortableObject reading process. Or {@code null} if object is not created from PortableObject.
-     */
+    /** Context of PortableObject reading process. Or {@code null} if object is not created from PortableObject. */
     private final PortableBuilderReader reader;
 
     /** */
@@ -115,6 +117,7 @@ public class PortableBuilderImpl implements PortableBuilder {
         this.ctx = ctx;
 
         start = -1;
+        flags = -1;
         reader = null;
         hdrLen = DFLT_HDR_LEN;
 
@@ -137,6 +140,7 @@ public class PortableBuilderImpl implements PortableBuilder {
     PortableBuilderImpl(PortableBuilderReader reader, int start) {
         this.reader = reader;
         this.start = start;
+        this.flags = reader.readShortPositioned(start + FLAGS_POS);
 
         byte ver = reader.readBytePositioned(start + PROTO_VER_POS);
 
@@ -198,184 +202,188 @@ public class PortableBuilderImpl implements PortableBuilder {
      * @param serializer Serializer.
      */
     void serializeTo(PortableWriterExImpl writer, PortableBuilderSerializer serializer) {
-        PortableUtils.writeHeader(writer,
-            true,
-            registeredType ? typeId : UNREGISTERED_TYPE_ID,
-            hashCode,
-            registeredType ? null : clsNameToWrite);
+        try {
+            PortableUtils.writeHeader(writer,
+                true,
+                registeredType ? typeId : UNREGISTERED_TYPE_ID,
+                hashCode,
+                registeredType ? null : clsNameToWrite);
 
-        Set<Integer> remainsFlds = null;
+            Set<Integer> remainsFlds = null;
 
-        if (reader != null) {
-            Map<Integer, Object> assignedFldsById;
+            if (reader != null) {
+                Map<Integer, Object> assignedFldsById;
 
-            if (assignedVals != null) {
-                assignedFldsById = U.newHashMap(assignedVals.size());
+                if (assignedVals != null) {
+                    assignedFldsById = U.newHashMap(assignedVals.size());
 
-                for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
-                    int fldId = ctx.fieldId(typeId, entry.getKey());
+                    for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
+                        int fldId = ctx.fieldId(typeId, entry.getKey());
 
-                    assignedFldsById.put(fldId, entry.getValue());
-                }
+                        assignedFldsById.put(fldId, entry.getValue());
+                    }
 
-                remainsFlds = assignedFldsById.keySet();
-            }
-            else
-                assignedFldsById = Collections.emptyMap();
+                    remainsFlds = assignedFldsById.keySet();
+                } else
+                    assignedFldsById = Collections.emptyMap();
 
-            // Get footer details.
-            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start);
+                // Get footer details.
+                int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
 
-            int footerPos = footer.get1();
-            int footerEnd = footer.get2();
+                IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
 
-            // Get raw position.
-            int rawPos = PortableUtils.rawOffsetAbsolute(reader, start);
+                int footerPos = footer.get1();
+                int footerEnd = footer.get2();
 
-            // Position reader on data.
-            reader.position(start + hdrLen);
+                // Get raw position.
+                int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
 
-            while (reader.position() < rawPos) {
-                int fieldId = reader.readIntPositioned(footerPos);
-                int fieldLen = fieldPositionAndLength(footerPos, footerEnd, rawPos).get2();
+                // Position reader on data.
+                reader.position(start + hdrLen);
 
-                footerPos += 8;
+                while (reader.position() + 4 < rawPos) {
+                    int fieldId = reader.readIntPositioned(footerPos);
+                    int fieldLen = fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize).get2();
 
-                if (assignedFldsById.containsKey(fieldId)) {
-                    Object assignedVal = assignedFldsById.remove(fieldId);
+                    footerPos += 4 + fieldOffsetSize;
 
-                    reader.skip(fieldLen);
+                    if (assignedFldsById.containsKey(fieldId)) {
+                        Object assignedVal = assignedFldsById.remove(fieldId);
 
-                    if (assignedVal != REMOVED_FIELD_MARKER) {
-                        writer.writeFieldId(fieldId);
+                        reader.skip(fieldLen);
 
-                        serializer.writeValue(writer, assignedVal);
-                    }
-                }
-                else {
-                    int type = fieldLen != 0 ? reader.readByte(0) : 0;
+                        if (assignedVal != REMOVED_FIELD_MARKER) {
+                            writer.writeFieldId(fieldId);
 
-                    if (fieldLen != 0 && !PortableUtils.isPlainArrayType(type) && PortableUtils.isPlainType(type)) {
-                        writer.writeFieldId(fieldId);
-                        writer.write(reader.array(), reader.position(), fieldLen);
+                            serializer.writeValue(writer, assignedVal);
+                        }
+                    } else {
+                        int type = fieldLen != 0 ? reader.readByte(0) : 0;
 
-                        reader.skip(fieldLen);
-                    }
-                    else {
-                        writer.writeFieldId(fieldId);
+                        if (fieldLen != 0 && !PortableUtils.isPlainArrayType(type) && PortableUtils.isPlainType(type)) {
+                            writer.writeFieldId(fieldId);
+                            writer.write(reader.array(), reader.position(), fieldLen);
 
-                        Object val;
+                            reader.skip(fieldLen);
+                        } else {
+                            writer.writeFieldId(fieldId);
 
-                        if (fieldLen == 0)
-                            val = null;
-                        else if (readCache == null) {
-                            int savedPos = reader.position();
+                            Object val;
 
-                            val = reader.parseValue();
+                            if (fieldLen == 0)
+                                val = null;
+                            else if (readCache == null) {
+                                int savedPos = reader.position();
 
-                            assert reader.position() == savedPos + fieldLen;
-                        }
-                        else {
-                            val = readCache.get(fieldId);
+                                val = reader.parseValue();
 
-                            reader.skip(fieldLen);
-                        }
+                                assert reader.position() == savedPos + fieldLen;
+                            } else {
+                                val = readCache.get(fieldId);
+
+                                reader.skip(fieldLen);
+                            }
 
-                        serializer.writeValue(writer, val);
+                            serializer.writeValue(writer, val);
+                        }
                     }
                 }
             }
-        }
-
-        if (assignedVals != null && (remainsFlds == null || !remainsFlds.isEmpty())) {
-            boolean metadataEnabled = ctx.isMetaDataEnabled(typeId);
 
-            PortableMetadata metadata = null;
+            if (assignedVals != null && (remainsFlds == null || !remainsFlds.isEmpty())) {
+                boolean metadataEnabled = ctx.isMetaDataEnabled(typeId);
 
-            if (metadataEnabled)
-                metadata = ctx.metaData(typeId);
+                PortableMetadata metadata = null;
 
-            Map<String, String> newFldsMetadata = null;
+                if (metadataEnabled)
+                    metadata = ctx.metaData(typeId);
 
-            for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
-                Object val = entry.getValue();
+                Map<String, String> newFldsMetadata = null;
 
-                if (val == REMOVED_FIELD_MARKER)
-                    continue;
-
-                String name = entry.getKey();
+                for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
+                    Object val = entry.getValue();
 
-                int fldId = ctx.fieldId(typeId, name);
+                    if (val == REMOVED_FIELD_MARKER)
+                        continue;
 
-                if (remainsFlds != null && !remainsFlds.contains(fldId))
-                    continue;
+                    String name = entry.getKey();
 
-                writer.writeFieldId(fldId);
+                    int fldId = ctx.fieldId(typeId, name);
 
-                serializer.writeValue(writer, val);
+                    if (remainsFlds != null && !remainsFlds.contains(fldId))
+                        continue;
 
-                if (metadataEnabled) {
-                    String oldFldTypeName = metadata == null ? null : metadata.fieldTypeName(name);
+                    writer.writeFieldId(fldId);
 
-                    String newFldTypeName;
+                    serializer.writeValue(writer, val);
 
-                    if (val instanceof PortableValueWithType)
-                        newFldTypeName = ((PortableValueWithType)val).typeName();
-                    else {
-                        byte type = PortableUtils.typeByClass(val.getClass());
+                    if (metadataEnabled) {
+                        String oldFldTypeName = metadata == null ? null : metadata.fieldTypeName(name);
 
-                        newFldTypeName = CacheObjectPortableProcessorImpl.fieldTypeName(type);
-                    }
+                        String newFldTypeName;
 
-                    if (oldFldTypeName == null) {
-                        // It's a new field, we have to add it to metadata.
+                        if (val instanceof PortableValueWithType)
+                            newFldTypeName = ((PortableValueWithType) val).typeName();
+                        else {
+                            byte type = PortableUtils.typeByClass(val.getClass());
 
-                        if (newFldsMetadata == null)
-                            newFldsMetadata = new HashMap<>();
+                            newFldTypeName = CacheObjectPortableProcessorImpl.fieldTypeName(type);
+                        }
 
-                        newFldsMetadata.put(name, newFldTypeName);
-                    }
-                    else {
-                        if (!"Object".equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
-                            throw new PortableException(
-                                "Wrong value has been set [" +
-                                    "typeName=" + (typeName == null ? metadata.typeName() : typeName) +
-                                    ", fieldName=" + name +
-                                    ", fieldType=" + oldFldTypeName +
-                                    ", assignedValueType=" + newFldTypeName +
-                                    ", assignedValue=" + (((PortableValueWithType)val).value()) + ']'
-                            );
+                        if (oldFldTypeName == null) {
+                            // It's a new field, we have to add it to metadata.
+
+                            if (newFldsMetadata == null)
+                                newFldsMetadata = new HashMap<>();
+
+                            newFldsMetadata.put(name, newFldTypeName);
+                        } else {
+                            if (!"Object".equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
+                                throw new PortableException(
+                                    "Wrong value has been set [" +
+                                        "typeName=" + (typeName == null ? metadata.typeName() : typeName) +
+                                        ", fieldName=" + name +
+                                        ", fieldType=" + oldFldTypeName +
+                                        ", assignedValueType=" + newFldTypeName +
+                                        ", assignedValue=" + (((PortableValueWithType) val).value()) + ']'
+                                );
+                            }
                         }
                     }
                 }
-            }
 
-            if (newFldsMetadata != null) {
-                String typeName = this.typeName;
+                if (newFldsMetadata != null) {
+                    String typeName = this.typeName;
 
-                if (typeName == null)
-                    typeName = metadata.typeName();
+                    if (typeName == null)
+                        typeName = metadata.typeName();
 
-                ctx.updateMetaData(typeId, typeName, newFldsMetadata);
+                    ctx.updateMetaData(typeId, typeName, newFldsMetadata);
+                }
             }
-        }
 
-        if (reader != null) {
-            // Write raw data if any.
-            int rawOff = PortableUtils.rawOffsetAbsolute(reader, start);
-            int footerStart = PortableUtils.footerStartAbsolute(reader, start);
+            if (reader != null) {
+                // Write raw data if any.
+                int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
+
+                int rawOff = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
+                int footerStart = PortableUtils.footerStartAbsolute(reader, start);
 
-            if (rawOff < footerStart) {
-                writer.rawWriter();
+                if (rawOff < footerStart) {
+                    writer.rawWriter();
 
-                writer.write(reader.array(), rawOff, footerStart - rawOff);
+                    writer.write(reader.array(), rawOff, footerStart - rawOff);
+                }
+
+                // Shift reader to the end of the object.
+                reader.position(start + PortableUtils.length(reader, start));
             }
 
-            // Shift reader to the end of the object.
-            reader.position(start + PortableUtils.length(reader, start));
+            writer.postWrite(true);
+        }
+        finally {
+            writer.popSchema();
         }
-
-        writer.postWrite(true);
     }
 
     /** {@inheritDoc} */
@@ -391,21 +399,25 @@ public class PortableBuilderImpl implements PortableBuilder {
      * @param footerPos Field position inside the footer (absolute).
      * @param footerEnd Footer end (absolute).
      * @param rawPos Raw data position (absolute).
+     * @param fieldOffsetSize Size of field's offset.
      * @return Tuple with field position and length.
      */
-    private IgniteBiTuple<Integer, Integer> fieldPositionAndLength(int footerPos, int footerEnd, int rawPos) {
-        int fieldOffset = reader.readIntPositioned(footerPos + 4);
+    private IgniteBiTuple<Integer, Integer> fieldPositionAndLength(int footerPos, int footerEnd, int rawPos,
+        int fieldOffsetSize) {
+        // Get field offset first.
+        int fieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4, fieldOffsetSize);
         int fieldPos = start + fieldOffset;
 
         // Get field length.
         int fieldLen;
 
-        if (footerPos + 8 == footerEnd)
+        if (footerPos + 4 + fieldOffsetSize == footerEnd)
             // This is the last field, compare to raw offset.
             fieldLen = rawPos - fieldPos;
         else {
             // Field is somewhere in the middle, get difference with the next offset.
-            int nextFieldOffset = reader.readIntPositioned(footerPos + 8 + 4);
+            int nextFieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4 + fieldOffsetSize + 4,
+                fieldOffsetSize);
 
             fieldLen = nextFieldOffset - fieldOffset;
         }
@@ -418,26 +430,29 @@ public class PortableBuilderImpl implements PortableBuilder {
      */
     private void ensureReadCacheInit() {
         if (readCache == null) {
+            int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
+
             Map<Integer, Object> readCache = new HashMap<>();
 
-            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start);
+            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
 
             int footerPos = footer.get1();
             int footerEnd = footer.get2();
 
-            int rawPos = PortableUtils.rawOffsetAbsolute(reader, start);
+            int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
 
-            while (footerPos < footerEnd) {
+            while (footerPos + 4 < footerEnd) {
                 int fieldId = reader.readIntPositioned(footerPos);
 
-                IgniteBiTuple<Integer, Integer> posAndLen = fieldPositionAndLength(footerPos, footerEnd, rawPos);
+                IgniteBiTuple<Integer, Integer> posAndLen =
+                    fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize);
 
                 Object val = reader.getValueQuickly(posAndLen.get1(), posAndLen.get2());
 
                 readCache.put(fieldId, val);
 
                 // Shift current footer position.
-                footerPos += 8;
+                footerPos += 4 + fieldOffsetSize;
             }
 
             this.readCache = readCache;

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core-test/src/portable_reader_writer_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core-test/src/portable_reader_writer_test.cpp b/modules/platforms/cpp/core-test/src/portable_reader_writer_test.cpp
index baeb9e7..3ec5a15 100644
--- a/modules/platforms/cpp/core-test/src/portable_reader_writer_test.cpp
+++ b/modules/platforms/cpp/core-test/src/portable_reader_writer_test.cpp
@@ -68,9 +68,9 @@ void CheckPrimitive(T val)
     in.Synchronize();
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8;
+    int32_t footerEnd = footerBegin + 5;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     try
@@ -148,9 +148,9 @@ void CheckPrimitiveArray(T dflt, T val1, T val2)
         in.Synchronize();
 
         int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-        int32_t footerEnd = footerBegin + 8;
+        int32_t footerEnd = footerBegin + 5;
 
-        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
         PortableReader reader(&readerImpl);
 
         in.Position(IGNITE_DFLT_HDR_LEN);
@@ -181,9 +181,9 @@ void CheckPrimitiveArray(T dflt, T val1, T val2)
         in.Synchronize();
 
         int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-        int32_t footerEnd = footerBegin + 8;
+        int32_t footerEnd = footerBegin + 5;
 
-        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
         PortableReader reader(&readerImpl);
 
         in.Position(IGNITE_DFLT_HDR_LEN);
@@ -218,9 +218,9 @@ void CheckPrimitiveArray(T dflt, T val1, T val2)
         in.Synchronize();
 
         int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-        int32_t footerEnd = footerBegin + 8;
+        int32_t footerEnd = footerBegin + 5;
 
-        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
         PortableReader reader(&readerImpl);
 
         in.Position(IGNITE_DFLT_HDR_LEN);
@@ -258,9 +258,9 @@ void CheckPrimitiveArray(T dflt, T val1, T val2)
         in.Synchronize();
 
         int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-        int32_t footerEnd = footerBegin + 8;
+        int32_t footerEnd = footerBegin + 5;
 
-        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+        PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
         PortableReader reader(&readerImpl);
 
         in.Position(IGNITE_DFLT_HDR_LEN);
@@ -510,9 +510,9 @@ void CheckCollectionEmpty(CollectionType* colType)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -600,9 +600,9 @@ void CheckCollection(CollectionType* colType)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -677,9 +677,9 @@ void CheckCollectionIterators(CollectionType* colType)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -753,9 +753,9 @@ void CheckMapEmpty(MapType* mapType)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -846,9 +846,9 @@ void CheckMap(MapType* mapType)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1028,9 +1028,9 @@ BOOST_AUTO_TEST_CASE(TestGuidNull)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8;
+    int32_t footerEnd = footerBegin + 5;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
     
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1113,9 +1113,9 @@ BOOST_AUTO_TEST_CASE(TestString) {
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 5;
+    int32_t footerEnd = footerBegin + 5 * 5;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1191,9 +1191,9 @@ BOOST_AUTO_TEST_CASE(TestStringArrayNull)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1308,9 +1308,9 @@ BOOST_AUTO_TEST_CASE(TestStringArrayEmpty)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1435,9 +1435,9 @@ BOOST_AUTO_TEST_CASE(TestStringArray)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1549,14 +1549,15 @@ BOOST_AUTO_TEST_CASE(TestObject)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 3;
+    int32_t footerEnd = footerBegin + 5 * 3;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN); 
 
     PortableInner readVal1 = reader.ReadObject<PortableInner>("field1");
+
     BOOST_REQUIRE(writeVal1.GetValue() == readVal1.GetValue());
 
     PortableInner readVal2 = reader.ReadObject<PortableInner>("field2");
@@ -1592,9 +1593,9 @@ BOOST_AUTO_TEST_CASE(TestNestedObject)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 3;
+    int32_t footerEnd = footerBegin + 5 * 3;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1634,9 +1635,9 @@ BOOST_AUTO_TEST_CASE(TestArrayNull)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1710,9 +1711,9 @@ BOOST_AUTO_TEST_CASE(TestArrayEmpty)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1794,9 +1795,9 @@ BOOST_AUTO_TEST_CASE(TestArray)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1855,9 +1856,9 @@ BOOST_AUTO_TEST_CASE(TestCollectionNull)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -1941,9 +1942,9 @@ BOOST_AUTO_TEST_CASE(TestMapNull)
     InteropInputStream in(&mem);
 
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
-    int32_t footerEnd = footerBegin + 8 * 2;
+    int32_t footerEnd = footerBegin + 5 * 2;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
 
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -2034,7 +2035,7 @@ BOOST_AUTO_TEST_CASE(TestRawMode)
     int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
     int32_t footerEnd = footerBegin;
 
-    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 1000, footerBegin, footerBegin, footerEnd);
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 1000, footerBegin, footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
     PortableReader reader(&readerImpl);
     
     in.Position(IGNITE_DFLT_HDR_LEN);
@@ -2111,7 +2112,7 @@ BOOST_AUTO_TEST_CASE(TestFieldSeek)
 
     PortableReaderImpl readerImpl(&in, &idRslvr, pos, usrType, 
                                   typeId, hashCode, len, rawOff, 
-                                  footerBegin, footerEnd);
+                                  footerBegin, footerEnd, OFFSET_TYPE_1_BYTE);
 
     PortableReader reader(&readerImpl);
 
@@ -2211,4 +2212,162 @@ BOOST_AUTO_TEST_CASE(TestFieldSeek)
     BOOST_REQUIRE(mapReader.IsNull());
 }
 
+BOOST_AUTO_TEST_CASE(TestSchemaOffset2ByteFields)
+{
+    const int fieldsNum = 64;
+
+    TemplatedPortableIdResolver<PortableDummy> idRslvr;
+
+    InteropUnpooledMemory mem(4096);
+
+    InteropOutputStream out(&mem);
+    PortableWriterImpl writerImpl(&out, &idRslvr, NULL, NULL, 0);
+    PortableWriter writer(&writerImpl);
+
+    out.Position(IGNITE_DFLT_HDR_LEN);
+
+    for (int i = 0; i < fieldsNum; ++i)
+    {
+        std::stringstream tmp;
+        tmp << "field" << i;
+
+        writer.WriteInt32(tmp.str().c_str(), i * 10);
+    }
+
+    writerImpl.PostWrite();
+
+    out.Synchronize();
+
+    InteropInputStream in(&mem);
+
+    int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
+    int32_t footerEnd = footerBegin + 6 * fieldsNum;
+
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_2_BYTE);
+    PortableReader reader(&readerImpl);
+
+    in.Position(IGNITE_DFLT_HDR_LEN);
+
+    for (int i = 0; i < fieldsNum; ++i)
+    {
+        std::stringstream tmp;
+        tmp << "field" << i;
+
+        BOOST_REQUIRE(reader.ReadInt32(tmp.str().c_str()) == i * 10);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(TestSchemaOffset4ByteFields)
+{
+    const int fieldsNum = 0x10000 / 4;
+
+    TemplatedPortableIdResolver<PortableDummy> idRslvr;
+
+    InteropUnpooledMemory mem(1024 * 1024);
+
+    InteropOutputStream out(&mem);
+    PortableWriterImpl writerImpl(&out, &idRslvr, NULL, NULL, 0);
+    PortableWriter writer(&writerImpl);
+
+    out.Position(IGNITE_DFLT_HDR_LEN);
+
+    for (int i = 0; i < fieldsNum; ++i)
+    {
+        std::stringstream tmp;
+        tmp << "field" << i;
+
+        writer.WriteInt32(tmp.str().c_str(), i * 10);
+    }
+
+    writerImpl.PostWrite();
+
+    out.Synchronize();
+
+    InteropInputStream in(&mem);
+
+    int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
+    int32_t footerEnd = footerBegin + 8 * fieldsNum;
+
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_4_BYTE);
+    PortableReader reader(&readerImpl);
+
+    in.Position(IGNITE_DFLT_HDR_LEN);
+
+    for (int i = 0; i < fieldsNum; ++i)
+    {
+        std::stringstream tmp;
+        tmp << "field" << i;
+
+        BOOST_REQUIRE(reader.ReadInt32(tmp.str().c_str()) == i * 10);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(TestSchemaOffset2ByteArray)
+{
+    TemplatedPortableIdResolver<PortableDummy> idRslvr;
+
+    InteropUnpooledMemory mem(4096);
+
+    InteropOutputStream out(&mem);
+    PortableWriterImpl writerImpl(&out, &idRslvr, NULL, NULL, 0);
+    PortableWriter writer(&writerImpl);
+
+    out.Position(IGNITE_DFLT_HDR_LEN);
+
+    int8_t dummyArray[256] = {};
+
+    writer.WriteInt8Array("field1", dummyArray, sizeof(dummyArray));
+    writer.WriteInt32("field2", 42);
+
+    writerImpl.PostWrite();
+
+    out.Synchronize();
+
+    InteropInputStream in(&mem);
+
+    int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
+    int32_t footerEnd = footerBegin + 6 * 2;
+
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_2_BYTE);
+    PortableReader reader(&readerImpl);
+
+    in.Position(IGNITE_DFLT_HDR_LEN);
+
+    BOOST_REQUIRE(reader.ReadInt32("field2") == 42);
+}
+
+BOOST_AUTO_TEST_CASE(TestSchemaOffset4ByteArray)
+{
+    TemplatedPortableIdResolver<PortableDummy> idRslvr;
+
+    InteropUnpooledMemory mem(1024 * 1024);
+
+    InteropOutputStream out(&mem);
+    PortableWriterImpl writerImpl(&out, &idRslvr, NULL, NULL, 0);
+    PortableWriter writer(&writerImpl);
+
+    out.Position(IGNITE_DFLT_HDR_LEN);
+
+    int8_t dummyArray[0x10000] = {};
+
+    writer.WriteInt8Array("field1", dummyArray, sizeof(dummyArray));
+    writer.WriteInt32("field2", 42);
+
+    writerImpl.PostWrite();
+
+    out.Synchronize();
+
+    InteropInputStream in(&mem);
+
+    int32_t footerBegin = in.ReadInt32(IGNITE_OFFSET_SCHEMA_OR_RAW_OFF);
+    int32_t footerEnd = footerBegin + 8 * 2;
+
+    PortableReaderImpl readerImpl(&in, &idRslvr, 0, true, idRslvr.GetTypeId(), 0, 100, 100, footerBegin, footerEnd, OFFSET_TYPE_4_BYTE);
+    PortableReader reader(&readerImpl);
+
+    in.Position(IGNITE_DFLT_HDR_LEN);
+
+    BOOST_REQUIRE(reader.ReadInt32("field2") == 42);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/include/ignite/impl/interop/interop_input_stream.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/interop/interop_input_stream.h b/modules/platforms/cpp/core/include/ignite/impl/interop/interop_input_stream.h
index f23cec6..6842990 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/interop/interop_input_stream.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/interop/interop_input_stream.h
@@ -44,6 +44,14 @@ namespace ignite
                  * @return Value.
                  */
                 int8_t ReadInt8();
+
+                /**
+                 * Read signed 8-byte int at the given position.
+                 *
+                 * @param pos Position.
+                 * @return Value.
+                 */
+                int32_t ReadInt8(int32_t pos);
                     
                 /**
                  * Read signed 8-byte int array.
@@ -76,6 +84,14 @@ namespace ignite
                 int16_t ReadInt16();
 
                 /**
+                 * Read signed 16-byte int at the given position.
+                 *
+                 * @param pos Position.
+                 * @return Value.
+                 */
+                int32_t ReadInt16(int32_t pos);
+
+                /**
                  * Read signed 16-byte int array.
                  *
                  * @param res Allocated array.

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/include/ignite/impl/interop/interop_output_stream.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/interop/interop_output_stream.h b/modules/platforms/cpp/core/include/ignite/impl/interop/interop_output_stream.h
index 211ac6d..0814c01 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/interop/interop_output_stream.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/interop/interop_output_stream.h
@@ -83,6 +83,14 @@ namespace ignite
                 void WriteInt16(const int16_t val);
 
                 /**
+                 * Write signed 16-byte integer at the given position.
+                 *
+                 * @param pos Position.
+                 * @param val Value.
+                 */
+                void WriteInt16(const int32_t pos, const int16_t val);
+
+                /**
                  * Write signed 16-byte integer array.
                  *
                  * @param val Value.

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/include/ignite/impl/portable/portable_common.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_common.h b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_common.h
index c6dad50..f08c49b 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_common.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_common.h
@@ -169,6 +169,12 @@ namespace ignite
 
             /** Raw only flag. */
             const int16_t IGNITE_PORTABLE_FLAG_RAW_ONLY = 0x0002;
+
+            /** Flag indicating that schema field offset is one byte long. */
+            const int16_t IGNITE_PORTABLE_FLAG_OFFSET_1_BYTE = 0x0004;
+
+            /** Flag indicating that schema field offset is two byte long. */
+            const int16_t IGNITE_PORTABLE_FLAG_OFFSET_2_BYTE = 0x0008;
         }
     }    
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/include/ignite/impl/portable/portable_reader_impl.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_reader_impl.h b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_reader_impl.h
index fe25c87..4762fff 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_reader_impl.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_reader_impl.h
@@ -59,7 +59,7 @@ namespace ignite
                  */
                 PortableReaderImpl(interop::InteropInputStream* stream, PortableIdResolver* idRslvr,
                     int32_t pos, bool usrType, int32_t typeId, int32_t hashCode, int32_t len, int32_t rawOff,
-                    int32_t footerBegin, int32_t footerEnd);
+                    int32_t footerBegin, int32_t footerEnd, PortableOffsetType schemaType);
 
                 /**
                  * Constructor used to construct light-weight reader allowing only raw operations 
@@ -788,7 +788,27 @@ namespace ignite
                             else
                                 footerBegin = schemaOrRawOff;
 
-                            int32_t trailingBytes = (len - footerBegin) % 8;
+                            PortableOffsetType schemaType;
+                            int32_t trailingBytes;
+
+                            if (flags & IGNITE_PORTABLE_FLAG_OFFSET_1_BYTE)
+                            {
+                                schemaType = OFFSET_TYPE_1_BYTE;
+
+                                trailingBytes = (len - footerBegin) % 5;
+                            }
+                            else if (flags & IGNITE_PORTABLE_FLAG_OFFSET_2_BYTE)
+                            {
+                                schemaType = OFFSET_TYPE_2_BYTE;
+
+                                trailingBytes = (len - footerBegin) % 6;
+                            }
+                            else
+                            {
+                                schemaType = OFFSET_TYPE_4_BYTE;
+
+                                trailingBytes = (len - footerBegin) % 8;
+                            }
 
                             int32_t footerEnd = len - trailingBytes;
 
@@ -806,7 +826,7 @@ namespace ignite
                             TemplatedPortableIdResolver<T> idRslvr(type);
                             PortableReaderImpl readerImpl(stream, &idRslvr, pos, usrType,
                                                           typeId, hashCode, len, rawOff,
-                                                          footerBegin, footerEnd);
+                                                          footerBegin, footerEnd, schemaType);
                             ignite::portable::PortableReader reader(&readerImpl);
 
                             T val = type.Read(reader);
@@ -887,6 +907,9 @@ namespace ignite
                 /** Footer ending position. */
                 int32_t footerEnd;
 
+                /** Object schema type. */
+                PortableOffsetType schemaType;
+
                 IGNITE_NO_COPY_ASSIGNMENT(PortableReaderImpl)
                     
                 /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/include/ignite/impl/portable/portable_schema.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_schema.h b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_schema.h
index 1795fd1..4919e2a 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/portable/portable_schema.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/portable/portable_schema.h
@@ -34,6 +34,21 @@ namespace ignite
             class PortableWriterImpl;
 
             /**
+             * Schema size variants.
+             */
+            enum PortableOffsetType
+            {
+                /** Means all field offsets can be fit in one byte. */
+                OFFSET_TYPE_1_BYTE,
+
+                /** Means all field offsets can be fit in two bytes. */
+                OFFSET_TYPE_2_BYTE,
+
+                /** Means field offsets should be stored in four bytes. */
+                OFFSET_TYPE_4_BYTE
+            };
+
+            /**
              * Portable schema.
              */
             class IGNITE_IMPORT_EXPORT PortableSchema
@@ -86,10 +101,17 @@ namespace ignite
                  */
                 void Clear();
 
+                /**
+                 * Get type of schema.
+                 *
+                 * @return Type of schema.
+                 */
+                PortableOffsetType GetType() const;
+
             private:
                 /**
-                * Single schema field info.
-                */
+                 * Single schema field info.
+                 */
                 struct PortableSchemaFieldInfo
                 {
                     int32_t id;

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/src/impl/interop/interop_input_stream.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/interop/interop_input_stream.cpp b/modules/platforms/cpp/core/src/impl/interop/interop_input_stream.cpp
index 02e894c..fed7871 100644
--- a/modules/platforms/cpp/core/src/impl/interop/interop_input_stream.cpp
+++ b/modules/platforms/cpp/core/src/impl/interop/interop_input_stream.cpp
@@ -69,6 +69,16 @@ namespace ignite
                 IGNITE_INTEROP_IN_READ(int8_t, 1);
             }
 
+            int32_t InteropInputStream::ReadInt8(int32_t pos)
+            {
+                int delta = pos + 1 - this->pos;
+
+                if (delta > 0)
+                    EnsureEnoughData(delta);
+
+                return *reinterpret_cast<int8_t*>(data + pos);
+            }
+
             void InteropInputStream::ReadInt8Array(int8_t* const res, const int32_t len)
             {
                 IGNITE_INTEROP_IN_READ_ARRAY(len, 0);
@@ -90,6 +100,16 @@ namespace ignite
                 IGNITE_INTEROP_IN_READ(int16_t, 2);
             }
 
+            int32_t InteropInputStream::ReadInt16(int32_t pos)
+            {
+                int delta = pos + 2 - this->pos;
+
+                if (delta > 0)
+                    EnsureEnoughData(delta);
+
+                return *reinterpret_cast<int16_t*>(data + pos);
+            }
+
             void InteropInputStream::ReadInt16Array(int16_t* const res, const int32_t len)
             {
                 IGNITE_INTEROP_IN_READ_ARRAY(len, 1);

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/src/impl/interop/interop_output_stream.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/interop/interop_output_stream.cpp b/modules/platforms/cpp/core/src/impl/interop/interop_output_stream.cpp
index 1fd400b..acfd3ec 100644
--- a/modules/platforms/cpp/core/src/impl/interop/interop_output_stream.cpp
+++ b/modules/platforms/cpp/core/src/impl/interop/interop_output_stream.cpp
@@ -96,6 +96,13 @@ namespace ignite
                 IGNITE_INTEROP_OUT_WRITE(val, int16_t, 2);
             }
 
+            void InteropOutputStream::WriteInt16(const int32_t pos, const int16_t val)
+            {
+                EnsureCapacity(pos + 2);
+
+                *reinterpret_cast<int16_t*>(data + pos) = val;
+            }
+
             void InteropOutputStream::WriteInt16Array(const int16_t* val, const int32_t len)
             {
                 IGNITE_INTEROP_OUT_WRITE_ARRAY(val, len << 1);

http://git-wip-us.apache.org/repos/asf/ignite/blob/845c4f27/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp b/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp
index 96378e0..fd2cc18 100644
--- a/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/portable/portable_reader_impl.cpp
@@ -36,10 +36,10 @@ namespace ignite
         {
             PortableReaderImpl::PortableReaderImpl(InteropInputStream* stream, PortableIdResolver* idRslvr,
                 int32_t pos, bool usrType, int32_t typeId, int32_t hashCode, int32_t len, int32_t rawOff,
-                int32_t footerBegin, int32_t footerEnd) :
+                int32_t footerBegin, int32_t footerEnd, PortableOffsetType schemaType) :
                 stream(stream), idRslvr(idRslvr), pos(pos), usrType(usrType), typeId(typeId), 
                 hashCode(hashCode), len(len), rawOff(rawOff), rawMode(false), elemIdGen(0), elemId(0),
-                elemCnt(-1), elemRead(0), footerBegin(footerBegin), footerEnd(footerEnd)
+                elemCnt(-1), elemRead(0), footerBegin(footerBegin), footerEnd(footerEnd), schemaType(schemaType)
             {
                 // No-op.
             }
@@ -47,7 +47,7 @@ namespace ignite
             PortableReaderImpl::PortableReaderImpl(InteropInputStream* stream) :
                 stream(stream), idRslvr(NULL), pos(0), usrType(false), typeId(0), hashCode(0), len(0),
                 rawOff(0), rawMode(true), elemIdGen(0), elemId(0), elemCnt(-1), elemRead(0), footerBegin(-1),
-                footerEnd(-1)
+                footerEnd(-1), schemaType(OFFSET_TYPE_4_BYTE)
             {
                 // No-op.
             }
@@ -648,12 +648,43 @@ namespace ignite
 
                 stream->Position(footerBegin);
 
-                for (int32_t schemaPos = footerBegin; schemaPos < footerEnd; schemaPos += 8)
+                switch (schemaType)
                 {
-                    int32_t currentFieldId = stream->ReadInt32(schemaPos);
+                    case OFFSET_TYPE_1_BYTE:
+                    {
+                        for (int32_t schemaPos = footerBegin; schemaPos < footerEnd; schemaPos += 5)
+                        {
+                            int32_t currentFieldId = stream->ReadInt32(schemaPos);
+
+                            if (fieldId == currentFieldId)
+                                return static_cast<uint8_t>(stream->ReadInt8(schemaPos + 4)) + pos;
+                        }
+                        break;
+                    }
+
+                    case OFFSET_TYPE_2_BYTE:
+                    {
+                        for (int32_t schemaPos = footerBegin; schemaPos < footerEnd; schemaPos += 6)
+                        {
+                            int32_t currentFieldId = stream->ReadInt32(schemaPos);
 
-                    if (fieldId == currentFieldId)
-                        return stream->ReadInt32(schemaPos + 4) + pos;
+                            if (fieldId == currentFieldId)
+                                return static_cast<uint16_t>(stream->ReadInt16(schemaPos + 4)) + pos;
+                        }
+                        break;
+                    }
+
+                    case OFFSET_TYPE_4_BYTE:
+                    {
+                        for (int32_t schemaPos = footerBegin; schemaPos < footerEnd; schemaPos += 8)
+                        {
+                            int32_t currentFieldId = stream->ReadInt32(schemaPos);
+
+                            if (fieldId == currentFieldId)
+                                return stream->ReadInt32(schemaPos + 4) + pos;
+                        }
+                        break;
+                    }
                 }
 
                 return -1;