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/10/30 13:22:16 UTC

[6/6] ignite git commit: IGNITE-1770: Implemented constant-time field lookup on protocol level.

IGNITE-1770: Implemented constant-time field lookup on protocol level.


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

Branch: refs/heads/ignite-1282
Commit: b85fa1714d40daa4a47b7cb0449b5f1712fa0a0b
Parents: 667c2e6
Author: vozerov-gridgain <vo...@gridgain.com>
Authored: Fri Oct 30 15:22:45 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Fri Oct 30 15:22:45 2015 +0300

----------------------------------------------------------------------
 .../portable/GridPortableMarshaller.java        |   26 +-
 .../portable/PortableClassDescriptor.java       |  121 +-
 .../internal/portable/PortableContext.java      |   95 +
 .../internal/portable/PortableObjectEx.java     |    9 +
 .../internal/portable/PortableObjectImpl.java   |   12 +-
 .../portable/PortableObjectOffheapImpl.java     |   15 +-
 .../internal/portable/PortableObjectSchema.java |   63 +
 .../portable/PortablePositionReadable.java      |   39 +
 .../portable/PortableReaderContext.java         |   37 +-
 .../internal/portable/PortableReaderExImpl.java | 1734 ++++++------------
 .../ignite/internal/portable/PortableUtils.java |  159 +-
 .../internal/portable/PortableWriterExImpl.java |  555 +++---
 .../portable/builder/PortableBuilderImpl.java   |  196 +-
 .../portable/builder/PortableBuilderReader.java |   22 +-
 .../builder/PortableBuilderSerializer.java      |    6 +-
 .../portable/builder/PortableLazyArrayList.java |    6 +-
 .../builder/PortableLazyLinkedList.java         |    6 +-
 .../portable/builder/PortableLazyMap.java       |    6 +-
 .../portable/builder/PortableLazySet.java       |    4 +-
 .../streams/PortableAbstractInputStream.java    |   24 +-
 .../streams/PortableAbstractOutputStream.java   |   15 +
 .../streams/PortableHeapInputStream.java        |   12 +-
 .../streams/PortableHeapOutputStream.java       |    8 +
 .../portable/streams/PortableInputStream.java   |   12 +-
 .../streams/PortableOffheapInputStream.java     |   12 +-
 .../streams/PortableOffheapOutputStream.java    |    8 +
 .../portable/streams/PortableOutputStream.java  |    8 +
 .../CacheObjectPortableProcessorImpl.java       |    6 +-
 .../PlatformBigEndianInputStreamImpl.java       |    9 +-
 .../PlatformBigEndianOutputStreamImpl.java      |    5 +
 .../memory/PlatformInputStreamImpl.java         |   12 +-
 .../memory/PlatformOutputStreamImpl.java        |    7 +
 .../marshaller/portable/PortableMarshaller.java |    2 +-
 .../GridPortableMarshallerSelfTest.java         |   55 +-
 .../src/portable_reader_writer_test.cpp         |  555 ++++--
 modules/platforms/cpp/core/Makefile.am          |    1 +
 modules/platforms/cpp/core/include/Makefile.am  |    1 +
 .../ignite/impl/interop/interop_output_stream.h |    8 +
 .../ignite/impl/portable/portable_common.h      |   33 +-
 .../ignite/impl/portable/portable_reader_impl.h |  241 ++-
 .../ignite/impl/portable/portable_schema.h      |  114 ++
 .../ignite/impl/portable/portable_writer_impl.h |  105 +-
 .../platforms/cpp/core/project/vs/core.vcxproj  |    2 +
 .../cpp/core/project/vs/core.vcxproj.filters    |    6 +
 .../src/impl/interop/interop_input_stream.cpp   |    2 +-
 .../src/impl/interop/interop_output_stream.cpp  |   11 +
 .../src/impl/portable/portable_reader_impl.cpp  |  218 ++-
 .../core/src/impl/portable/portable_schema.cpp  |   88 +
 .../src/impl/portable/portable_writer_impl.cpp  |  100 +-
 .../Portable/PortableWriteBenchmark.cs          |    4 +-
 .../Apache.Ignite.Core.csproj                   |    5 +
 .../Apache.Ignite.Core/Impl/Common/Fnv1Hash.cs  |   54 +
 .../Impl/Common/ResizeableArray.cs              |   70 +
 .../Impl/Memory/PlatformMemoryStream.cs         |   35 +-
 .../Impl/Portable/IPortableTypeDescriptor.cs    |    5 +
 .../Impl/Portable/Io/IPortableStream.cs         |    8 +-
 .../Impl/Portable/Io/PortableAbstractStream.cs  |   72 +-
 .../Impl/Portable/Io/PortableHeapStream.cs      |   99 +-
 .../Impl/Portable/PortableBuilderImpl.cs        |  145 +-
 .../Impl/Portable/PortableFullTypeDescriptor.cs |    9 +
 .../Impl/Portable/PortableMarshaller.cs         |    2 +-
 .../Impl/Portable/PortableObjectHeader.cs       |  343 ++++
 .../Impl/Portable/PortableObjectSchema.cs       |   98 +
 .../Impl/Portable/PortableObjectSchemaField.cs  |  113 ++
 .../Impl/Portable/PortableReaderImpl.cs         |  173 +-
 .../Portable/PortableSurrogateTypeDescriptor.cs |    9 +
 .../Impl/Portable/PortableUserObject.cs         |   82 +-
 .../Impl/Portable/PortableUtils.cs              |  103 +-
 .../Impl/Portable/PortableWriterImpl.cs         |  164 +-
 .../Impl/Portable/PortablesImpl.cs              |   16 +-
 .../Structure/PortableStructureTracker.cs       |    8 +
 parent/pom.xml                                  |    8 +-
 72 files changed, 3703 insertions(+), 2713 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
index 6f16755..9afe2ee 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
@@ -198,23 +198,26 @@ public class GridPortableMarshaller {
     /** Protocol version position. */
     public static final int PROTO_VER_POS = 1;
 
-    /** */
-    public static final int TYPE_ID_POS = 3;
+    /** Flags position in header. */
+    public static final int FLAGS_POS = 2;
 
     /** */
-    public static final int HASH_CODE_POS = 7;
+    public static final int TYPE_ID_POS = 4;
 
     /** */
-    public static final int TOTAL_LEN_POS = 11;
+    public static final int HASH_CODE_POS = 8;
 
     /** */
-    public static final byte RAW_DATA_OFF_POS = 15;
+    public static final int TOTAL_LEN_POS = 12;
 
     /** */
-    public static final int CLS_NAME_POS = 19;
+    public static final int SCHEMA_ID_POS = 16;
+
+    /** Schema or raw offset position. */
+    public static final int SCHEMA_OR_RAW_OFF_POS = 20;
 
     /** */
-    public static final byte DFLT_HDR_LEN = 19;
+    public static final byte DFLT_HDR_LEN = 24;
 
     /** */
     private final PortableContext ctx;
@@ -228,16 +231,15 @@ public class GridPortableMarshaller {
 
     /**
      * @param obj Object to marshal.
-     * @param off Offset.
      * @return Byte array.
      * @throws PortableException In case of error.
      */
-    public byte[] marshal(@Nullable Object obj, int off) throws PortableException {
+    public byte[] marshal(@Nullable Object obj) throws PortableException {
         if (obj == null)
             return new byte[] { NULL };
 
-        try (PortableWriterExImpl writer = new PortableWriterExImpl(ctx, off)) {
-            writer.marshal(obj, false);
+        try (PortableWriterExImpl writer = new PortableWriterExImpl(ctx)) {
+            writer.marshal(obj);
 
             return writer.array();
         }
@@ -293,7 +295,7 @@ public class GridPortableMarshaller {
      * @return Writer.
      */
     public PortableWriterExImpl writer(PortableOutputStream out) {
-        return new PortableWriterExImpl(ctx, out, 0);
+        return new PortableWriterExImpl(ctx, out);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/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 0a9974e..9f7f0c6 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
@@ -17,6 +17,18 @@
 
 package org.apache.ignite.internal.portable;
 
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.cache.CacheObjectImpl;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.marshaller.MarshallerExclusions;
+import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
+import org.apache.ignite.marshaller.portable.PortableMarshaller;
+import org.apache.ignite.portable.PortableException;
+import org.apache.ignite.portable.PortableIdMapper;
+import org.apache.ignite.portable.PortableMarshalAware;
+import org.apache.ignite.portable.PortableSerializer;
+import org.jetbrains.annotations.Nullable;
+
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -35,17 +47,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.UUID;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.processors.cache.CacheObjectImpl;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.marshaller.MarshallerExclusions;
-import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
-import org.apache.ignite.marshaller.portable.PortableMarshaller;
-import org.apache.ignite.portable.PortableException;
-import org.apache.ignite.portable.PortableIdMapper;
-import org.apache.ignite.portable.PortableMarshalAware;
-import org.apache.ignite.portable.PortableSerializer;
-import org.jetbrains.annotations.Nullable;
 
 import static java.lang.reflect.Modifier.isStatic;
 import static java.lang.reflect.Modifier.isTransient;
@@ -63,6 +64,9 @@ public class PortableClassDescriptor {
     /** */
     private final PortableSerializer serializer;
 
+    /** ID mapper. */
+    private final PortableIdMapper idMapper;
+
     /** */
     private final Mode mode;
 
@@ -138,6 +142,7 @@ public class PortableClassDescriptor {
         this.typeId = typeId;
         this.typeName = typeName;
         this.serializer = serializer;
+        this.idMapper = idMapper;
         this.keepDeserialized = keepDeserialized;
         this.registered = registered;
 
@@ -307,6 +312,15 @@ public class PortableClassDescriptor {
     }
 
     /**
+     * Get ID mapper.
+     *
+     * @return ID mapper.
+     */
+    public PortableIdMapper idMapper() {
+        return idMapper;
+    }
+
+    /**
      * @return portableWriteReplace() method
      */
     @Nullable Method getWriteReplaceMethod() {
@@ -409,57 +423,57 @@ public class PortableClassDescriptor {
                 break;
 
             case SHORT_ARR:
-                writer.doWriteShortArray((short[])obj);
+                writer.doWriteShortArray((short[]) obj);
 
                 break;
 
             case INT_ARR:
-                writer.doWriteIntArray((int[])obj);
+                writer.doWriteIntArray((int[]) obj);
 
                 break;
 
             case LONG_ARR:
-                writer.doWriteLongArray((long[])obj);
+                writer.doWriteLongArray((long[]) obj);
 
                 break;
 
             case FLOAT_ARR:
-                writer.doWriteFloatArray((float[])obj);
+                writer.doWriteFloatArray((float[]) obj);
 
                 break;
 
             case DOUBLE_ARR:
-                writer.doWriteDoubleArray((double[])obj);
+                writer.doWriteDoubleArray((double[]) obj);
 
                 break;
 
             case CHAR_ARR:
-                writer.doWriteCharArray((char[])obj);
+                writer.doWriteCharArray((char[]) obj);
 
                 break;
 
             case BOOLEAN_ARR:
-                writer.doWriteBooleanArray((boolean[])obj);
+                writer.doWriteBooleanArray((boolean[]) obj);
 
                 break;
 
             case DECIMAL_ARR:
-                writer.doWriteDecimalArray((BigDecimal[])obj);
+                writer.doWriteDecimalArray((BigDecimal[]) obj);
 
                 break;
 
             case STRING_ARR:
-                writer.doWriteStringArray((String[])obj);
+                writer.doWriteStringArray((String[]) obj);
 
                 break;
 
             case UUID_ARR:
-                writer.doWriteUuidArray((UUID[])obj);
+                writer.doWriteUuidArray((UUID[]) obj);
 
                 break;
 
             case DATE_ARR:
-                writer.doWriteDateArray((Date[])obj);
+                writer.doWriteDateArray((Date[]) obj);
 
                 break;
 
@@ -515,8 +529,7 @@ public class PortableClassDescriptor {
                     else
                         ((PortableMarshalAware)obj).writePortable(writer);
 
-                    writer.writeRawOffsetIfNeeded();
-                    writer.writeLength();
+                    writer.postWrite(userType);
 
                     if (obj.getClass() != PortableMetaDataImpl.class
                         && ctx.isMetaDataChanged(typeId, writer.metaDataHashSum())) {
@@ -535,6 +548,8 @@ public class PortableClassDescriptor {
 
             case EXTERNALIZABLE:
                 if (writeHeader(obj, writer)) {
+                    writer.rawWriter();
+
                     try {
                         ((Externalizable)obj).writeExternal(writer);
                     }
@@ -542,7 +557,7 @@ public class PortableClassDescriptor {
                         throw new PortableException("Failed to write Externalizable object: " + obj, e);
                     }
 
-                    writer.writeLength();
+                    writer.postWrite(userType);
                 }
 
                 break;
@@ -552,8 +567,7 @@ public class PortableClassDescriptor {
                     for (FieldInfo info : fields)
                         info.write(obj, writer);
 
-                    writer.writeRawOffsetIfNeeded();
-                    writer.writeLength();
+                    writer.postWrite(userType);
                 }
 
                 break;
@@ -646,28 +660,13 @@ public class PortableClassDescriptor {
         if (writer.tryWriteAsHandle(obj))
             return false;
 
-        int pos = writer.position();
-
-        writer.doWriteByte(GridPortableMarshaller.OBJ);
-        writer.doWriteByte(GridPortableMarshaller.PROTO_VER);
-        writer.doWriteBoolean(userType);
-        writer.doWriteInt(registered ? typeId : GridPortableMarshaller.UNREGISTERED_TYPE_ID);
-        writer.doWriteInt(obj instanceof CacheObjectImpl ? 0 : obj.hashCode());
-
-        // For length and raw offset.
-        int reserved = writer.reserve(8);
-
-        // Class name in case if typeId registration is failed.
-        if (!registered)
-            writer.doWriteString(cls.getName());
-
-        int current = writer.position();
-        int len = current - pos;
-
-        // Default raw offset (equal to header length).
-        writer.position(reserved + 4);
-        writer.doWriteInt(len);
-        writer.position(current);
+        PortableUtils.writeHeader(
+            writer,
+            userType,
+            registered ? typeId : GridPortableMarshaller.UNREGISTERED_TYPE_ID,
+            obj instanceof CacheObjectImpl ? 0 : obj.hashCode(),
+            registered ? null : cls.getName()
+        );
 
         return true;
     }
@@ -859,7 +858,7 @@ public class PortableClassDescriptor {
             assert obj != null;
             assert writer != null;
 
-            writer.doWriteInt(id);
+            writer.writeFieldId(id);
 
             Object val;
 
@@ -942,57 +941,57 @@ public class PortableClassDescriptor {
                     break;
 
                 case SHORT_ARR:
-                    writer.writeShortArrayField((short[])val);
+                    writer.writeShortArrayField((short[]) val);
 
                     break;
 
                 case INT_ARR:
-                    writer.writeIntArrayField((int[])val);
+                    writer.writeIntArrayField((int[]) val);
 
                     break;
 
                 case LONG_ARR:
-                    writer.writeLongArrayField((long[])val);
+                    writer.writeLongArrayField((long[]) val);
 
                     break;
 
                 case FLOAT_ARR:
-                    writer.writeFloatArrayField((float[])val);
+                    writer.writeFloatArrayField((float[]) val);
 
                     break;
 
                 case DOUBLE_ARR:
-                    writer.writeDoubleArrayField((double[])val);
+                    writer.writeDoubleArrayField((double[]) val);
 
                     break;
 
                 case CHAR_ARR:
-                    writer.writeCharArrayField((char[])val);
+                    writer.writeCharArrayField((char[]) val);
 
                     break;
 
                 case BOOLEAN_ARR:
-                    writer.writeBooleanArrayField((boolean[])val);
+                    writer.writeBooleanArrayField((boolean[]) val);
 
                     break;
 
                 case DECIMAL_ARR:
-                    writer.writeDecimalArrayField((BigDecimal[])val);
+                    writer.writeDecimalArrayField((BigDecimal[]) val);
 
                     break;
 
                 case STRING_ARR:
-                    writer.writeStringArrayField((String[])val);
+                    writer.writeStringArrayField((String[]) val);
 
                     break;
 
                 case UUID_ARR:
-                    writer.writeUuidArrayField((UUID[])val);
+                    writer.writeUuidArrayField((UUID[]) val);
 
                     break;
 
                 case DATE_ARR:
-                    writer.writeDateArrayField((Date[])val);
+                    writer.writeDateArrayField((Date[]) val);
 
                     break;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
index 26e098f..3c08df6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
@@ -155,6 +155,9 @@ public class PortableContext implements Externalizable {
     /** */
     private boolean keepDeserialized;
 
+    /** Object schemas. */
+    private volatile Map<Integer, Object> schemas;
+
     /**
      * For {@link Externalizable}.
      */
@@ -854,6 +857,98 @@ public class PortableContext implements Externalizable {
     }
 
     /**
+     * Get schema for the given schema ID.
+     *
+     * @param schemaId Schema ID.
+     * @return Schema or {@code null} if there are no such schema.
+     */
+    @SuppressWarnings("unchecked")
+    @Nullable public PortableObjectSchema schema(int typeId, int schemaId) {
+        Map<Integer, Object> schemas0 = schemas;
+
+        if (schemas0 != null) {
+            Object typeSchemas = schemas0.get(typeId);
+
+            if (typeSchemas instanceof IgniteBiTuple) {
+                // The most common case goes first.
+                IgniteBiTuple<Integer, PortableObjectSchema> schema =
+                    (IgniteBiTuple<Integer, PortableObjectSchema>)typeSchemas;
+
+                if (schema.get1() == schemaId)
+                    return schema.get2();
+            }
+            else if (typeSchemas instanceof Map) {
+                Map<Integer, PortableObjectSchema> curSchemas = (Map<Integer, PortableObjectSchema>)typeSchemas;
+
+                return curSchemas.get(schemaId);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Add schema.
+     *
+     * @param schemaId Schema ID.
+     * @param newTypeSchema New schema.
+     */
+    @SuppressWarnings("unchecked")
+    public void addSchema(int typeId, int schemaId, PortableObjectSchema newTypeSchema) {
+        synchronized (this) {
+            if (schemas == null) {
+                // This is the very first schema recorded.
+                Map<Integer, Object> newSchemas = new HashMap<>();
+
+                newSchemas.put(typeId, new IgniteBiTuple<>(schemaId, newTypeSchema));
+
+                schemas = newSchemas;
+            }
+            else {
+                Object typeSchemas = schemas.get(typeId);
+
+                if (typeSchemas == null) {
+                    // This is the very first object schema.
+                    Map<Integer, Object> newSchemas = new HashMap<>(schemas);
+
+                    newSchemas.put(typeId, new IgniteBiTuple<>(schemaId, newTypeSchema));
+
+                    schemas = newSchemas;
+                }
+                else if (typeSchemas instanceof IgniteBiTuple) {
+                    IgniteBiTuple<Integer, PortableObjectSchema> typeSchema =
+                        (IgniteBiTuple<Integer, PortableObjectSchema>)typeSchemas;
+
+                    if (typeSchema.get1() != schemaId) {
+                        Map<Integer, PortableObjectSchema> newTypeSchemas = new HashMap();
+
+                        newTypeSchemas.put(typeSchema.get1(), typeSchema.get2());
+                        newTypeSchemas.put(schemaId, newTypeSchema);
+
+                        Map<Integer, Object> newSchemas = new HashMap<>(schemas);
+
+                        newSchemas.put(typeId, newTypeSchemas);
+
+                        schemas = newSchemas;
+                    }
+                }
+                else {
+                    Map<Integer, PortableObjectSchema> newTypeSchemas =
+                        new HashMap((Map<Integer, PortableObjectSchema>)typeSchemas);
+
+                    newTypeSchemas.put(schemaId, newTypeSchema);
+
+                    Map<Integer, Object> newSchemas = new HashMap<>(schemas);
+
+                    newSchemas.put(typeId, newTypeSchemas);
+
+                    schemas = newSchemas;
+                }
+            }
+        }
+    }
+
+    /**
      * Returns instance of {@link OptimizedMarshaller}.
      *
      * @return Optimized marshaller.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/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 fe4b628..ef9ee24 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
@@ -58,6 +58,15 @@ public abstract class PortableObjectEx implements PortableObject {
     public abstract long offheapAddress();
 
     /**
+     * Gets field value.
+     *
+     * @param fieldId Field ID.
+     * @return Field value.
+     * @throws PortableException In case of any other error.
+     */
+    @Nullable public abstract <F> F field(int fieldId) throws PortableException;
+
+    /**
      * @param ctx Reader context.
      * @param fieldName Field name.
      * @return Field name.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/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 b156eda..f1868b1 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
@@ -235,7 +235,15 @@ public final class PortableObjectImpl extends PortableObjectEx implements Extern
     @Nullable @Override public <F> F field(String fieldName) throws PortableException {
         PortableReaderExImpl reader = new PortableReaderExImpl(ctx, arr, start, null);
 
-        return (F)reader.unmarshal(fieldName);
+        return (F)reader.unmarshalField(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <F> F field(int fieldId) throws PortableException {
+        PortableReaderExImpl reader = new PortableReaderExImpl(ctx, arr, start, null);
+
+        return (F)reader.unmarshalField(fieldId);
     }
 
     /** {@inheritDoc} */
@@ -247,7 +255,7 @@ public final class PortableObjectImpl extends PortableObjectEx implements Extern
             null,
             rCtx);
 
-        return (F)reader.unmarshal(fieldName);
+        return (F)reader.unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/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 0dc8612..0b3e3ea 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
@@ -136,7 +136,18 @@ public class PortableObjectOffheapImpl extends PortableObjectEx implements Exter
             start,
             null);
 
-        return (F)reader.unmarshal(fieldName);
+        return (F)reader.unmarshalField(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <F> F field(int fieldId) throws PortableException {
+        PortableReaderExImpl reader = new PortableReaderExImpl(ctx,
+            new PortableOffheapInputStream(ptr, size, false),
+            start,
+            null);
+
+        return (F)reader.unmarshalField(fieldId);
     }
 
     /** {@inheritDoc} */
@@ -148,7 +159,7 @@ public class PortableObjectOffheapImpl extends PortableObjectEx implements Exter
             null,
             rCtx);
 
-        return (F)reader.unmarshal(fieldName);
+        return (F)reader.unmarshalField(fieldName);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectSchema.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectSchema.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectSchema.java
new file mode 100644
index 0000000..917ee73
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableObjectSchema.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import java.util.Map;
+
+/**
+ * Portable object schema.
+ */
+public class PortableObjectSchema {
+    /** Schema ID. */
+    private final int schemaId;
+
+    /** Fields. */
+    private final Map<Integer, Integer> fields;
+
+    /**
+     * Constructor.
+     *
+     * @param schemaId Schema ID.
+     * @param fields Fields.
+     */
+    public PortableObjectSchema(int schemaId, Map<Integer, Integer> fields) {
+        this.schemaId = schemaId;
+        this.fields = fields;
+    }
+
+    /**
+     * Get schema ID.
+     *
+     * @return Schema ID.
+     */
+    public int schemaId() {
+        return schemaId;
+    }
+
+    /**
+     * Get field offset position.
+     *
+     * @param fieldId Field ID.
+     * @return Field offset position.
+     */
+    public int fieldOffsetPosition(int fieldId) {
+        Integer pos = fields.get(fieldId);
+
+        return pos != null ? pos : 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/core/src/main/java/org/apache/ignite/internal/portable/PortablePositionReadable.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortablePositionReadable.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortablePositionReadable.java
new file mode 100644
index 0000000..7e8d9d3
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortablePositionReadable.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+/**
+ * Interface allowing for positioned read.
+ */
+public interface PortablePositionReadable {
+    /**
+     * Read short at the given position.
+     *
+     * @param pos Position.
+     * @return Value.
+     */
+    public short readShortPositioned(int pos);
+
+    /**
+     * Read integer at the given position.
+     *
+     * @param pos Position.
+     * @return Value.
+     */
+    public int readIntPositioned(int pos);
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b85fa171/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
index 2d4a1c3..51fc407 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
@@ -20,15 +20,16 @@ package org.apache.ignite.internal.portable;
 import java.util.HashMap;
 import java.util.Map;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.portable.PortableObject;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Reader context.
- */
+* Reader context.
+*/
 class PortableReaderContext {
     /** */
-    private Map<Integer, Object> oHandles;
+    private Object oHandles;
 
     /** */
     private Map<Integer, PortableObject> poHandles;
@@ -37,13 +38,24 @@ class PortableReaderContext {
      * @param handle Handle.
      * @param obj Object.
      */
+    @SuppressWarnings("unchecked")
     void setObjectHandler(int handle, Object obj) {
         assert obj != null;
 
         if (oHandles == null)
-            oHandles = new HashMap<>(3, 1.0f);
+            oHandles = new IgniteBiTuple(handle, obj);
+        else if (oHandles instanceof IgniteBiTuple) {
+            Map map = new HashMap(3, 1.0f);
+
+            IgniteBiTuple t = (IgniteBiTuple)oHandles;
+
+            map.put(t.getKey(), t.getValue());
+            map.put(handle, obj);
 
-        oHandles.put(handle, obj);
+            oHandles = map;
+        }
+        else
+            ((Map)oHandles).put(handle, obj);
     }
 
     /**
@@ -64,7 +76,18 @@ class PortableReaderContext {
      * @return Object.
      */
     @Nullable Object getObjectByHandle(int handle) {
-        return oHandles != null ? oHandles.get(handle) : null;
+        if (oHandles != null) {
+            if (oHandles instanceof IgniteBiTuple) {
+                IgniteBiTuple t = (IgniteBiTuple)oHandles;
+
+                if ((int)t.get1() == handle)
+                    return t.get2();
+            }
+            else
+                return ((Map)oHandles).get(handle);
+        }
+
+        return null;
     }
 
     /**
@@ -79,4 +102,4 @@ class PortableReaderContext {
     @Override public String toString() {
         return S.toString(PortableReaderContext.class, this);
     }
-}
\ No newline at end of file
+}